AT_BANNER([ofproto])

AT_SETUP([ofproto - echo request])
OVS_VSWITCHD_START
AT_CHECK([ovs-ofctl -vwarn probe br0])
OVS_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([ofproto - handling messages with bad version])
AT_KEYWORDS([monitor])
OVS_VSWITCHD_START

# Start a monitor running OpenFlow 1.0, then send the switch an OF1.1 features
# request
AT_CHECK([ovs-ofctl -P standard monitor br0 --detach --no-chdir --pidfile])
ovs-appctl -t ovs-ofctl ofctl/set-output-file monitor.log
AT_CAPTURE_FILE([monitor.log])
ovs-appctl -t ovs-ofctl ofctl/send 0205000801234567
ovs-appctl -t ovs-ofctl ofctl/barrier
OVS_APP_EXIT_AND_WAIT([ovs-ofctl])

AT_CHECK([sed 's/ (xid=0x[[0-9a-fA-F]]*)//
/ECHO/d' monitor.log], [0], [dnl
send: OFPT_FEATURES_REQUEST (OF1.1):
OFPT_ERROR (OF1.1): OFPBRC_BAD_VERSION
OFPT_FEATURES_REQUEST (OF1.1):
OFPT_BARRIER_REPLY:
])

OVS_VSWITCHD_STOP(["/received OpenFlow version 0x02 != expected 01/d"])
AT_CLEANUP

AT_SETUP([ofproto - feature request, config request])
OVS_VSWITCHD_START
AT_CHECK([ovs-ofctl -vwarn show br0], [0], [stdout])
AT_CHECK([strip_xids < stdout], [0], [dnl
OFPT_FEATURES_REPLY: dpid:fedcba9876543210
n_tables:254, n_buffers:0
capabilities: FLOW_STATS TABLE_STATS PORT_STATS QUEUE_STATS ARP_MATCH_IP
actions: output enqueue set_vlan_vid set_vlan_pcp strip_vlan mod_dl_src mod_dl_dst mod_nw_src mod_nw_dst mod_nw_tos mod_tp_src mod_tp_dst
 LOCAL(br0): addr:aa:55:aa:55:00:00
     config:     0
     state:      0
     speed: 0 Mbps now, 0 Mbps max
OFPT_GET_CONFIG_REPLY: frags=normal miss_send_len=0
])
OVS_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([ofproto - set OpenFlow port number])
OVS_VSWITCHD_START(
       [add-port br0 p1 -- set Interface p1 type=dummy --\
        add-port br0 p2 -- set Interface p2 type=dummy ofport_request=99])
AT_CHECK([ovs-ofctl -vwarn show br0], [0], [stdout])
AT_CHECK([[sed '
s/ (xid=0x[0-9a-fA-F]*)//
s/00:0.$/00:0x/' < stdout]],
      [0], [dnl
OFPT_FEATURES_REPLY: dpid:fedcba9876543210
n_tables:254, n_buffers:0
capabilities: FLOW_STATS TABLE_STATS PORT_STATS QUEUE_STATS ARP_MATCH_IP
actions: output enqueue set_vlan_vid set_vlan_pcp strip_vlan mod_dl_src mod_dl_dst mod_nw_src mod_nw_dst mod_nw_tos mod_tp_src mod_tp_dst
 1(p1): addr:aa:55:aa:55:00:0x
     config:     0
     state:      0
     speed: 0 Mbps now, 0 Mbps max
 99(p2): addr:aa:55:aa:55:00:0x
     config:     0
     state:      0
     speed: 0 Mbps now, 0 Mbps max
 LOCAL(br0): addr:aa:55:aa:55:00:0x
     config:     0
     state:      0
     speed: 0 Mbps now, 0 Mbps max
OFPT_GET_CONFIG_REPLY: frags=normal miss_send_len=0
])

OVS_VSWITCHD_STOP
AT_CLEANUP

dnl This is really bare-bones.
dnl It at least checks request and reply serialization and deserialization.
AT_SETUP([ofproto - port stats - (OpenFlow 1.0)])
OVS_VSWITCHD_START
AT_CHECK([ovs-ofctl -vwarn dump-ports br0], [0], [stdout])
AT_CHECK([strip_xids < stdout], [0], [dnl
OFPST_PORT reply: 1 ports
  port LOCAL: rx pkts=0, bytes=0, drop=?, errs=?, frame=?, over=?, crc=?
           tx pkts=0, bytes=0, drop=?, errs=?, coll=?
])
OVS_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([ofproto - port stats - (OpenFlow 1.2)])
OVS_VSWITCHD_START
AT_CHECK([ovs-ofctl -O OpenFlow12 -vwarn dump-ports br0], [0], [stdout])
AT_CHECK([strip_xids < stdout], [0], [dnl
OFPST_PORT reply (OF1.2): 1 ports
  port LOCAL: rx pkts=0, bytes=0, drop=?, errs=?, frame=?, over=?, crc=?
           tx pkts=0, bytes=0, drop=?, errs=?, coll=?
])
OVS_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([ofproto - port stats - (OpenFlow 1.4)])
OVS_VSWITCHD_START
AT_CHECK([ovs-ofctl -O OpenFlow14 -vwarn dump-ports br0], [0], [stdout])
AT_CHECK([strip_xids < stdout | sed 's/duration=[[0-9.]]*s/duration=?s/'],
  [0], [dnl
OFPST_PORT reply (OF1.4): 1 ports
  port LOCAL: rx pkts=0, bytes=0, drop=?, errs=?, frame=?, over=?, crc=?
           tx pkts=0, bytes=0, drop=?, errs=?, coll=?
           duration=?s
           CUSTOM Statistics
                      rx_custom_packets_1=0, rx_custom_packets_2=0, rx_q0_bytes=0,
                      rx_q0_packets=0, tx_q0_bytes=0, tx_q0_packets=0,
])
OVS_VSWITCHD_STOP
AT_CLEANUP

dnl This is really bare-bones.
dnl It at least checks request and reply serialization and deserialization.
AT_SETUP([ofproto - port-desc stats (OpenFlow 1.0)])
OVS_VSWITCHD_START
AT_CHECK([ovs-ofctl -vwarn dump-ports-desc br0], [0], [stdout])
AT_CHECK([strip_xids < stdout], [0], [dnl
OFPST_PORT_DESC reply:
 LOCAL(br0): addr:aa:55:aa:55:00:00
     config:     0
     state:      0
     speed: 0 Mbps now, 0 Mbps max
])
OVS_VSWITCHD_STOP
AT_CLEANUP

dnl This is really bare-bones.
dnl It at least checks request and reply serialization and deserialization.
AT_SETUP([ofproto - port-desc stats (OpenFlow 1.2)])
OVS_VSWITCHD_START
AT_CHECK([ovs-ofctl -O OpenFlow12 -vwarn dump-ports-desc br0], [0], [stdout])
AT_CHECK([strip_xids < stdout], [0], [dnl
OFPST_PORT_DESC reply (OF1.2):
 LOCAL(br0): addr:aa:55:aa:55:00:00
     config:     0
     state:      LIVE
     speed: 0 Mbps now, 0 Mbps max
])
OVS_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([ofproto - port-desc stats (OpenFlow 1.5)])
OVS_VSWITCHD_START
add_of_ports br0 1 2 3
AT_CHECK([ovs-ofctl -F OXM-OpenFlow15 -O OpenFlow15 -vwarn dump-ports-desc br0], [0], [stdout])
AT_CHECK([strip_xids < stdout | sed 's/00:0./00:0x/'], [0], [dnl
OFPST_PORT_DESC reply (OF1.5):
 1(p1): addr:aa:55:aa:55:00:0x
     config:     0
     state:      LIVE
     speed: 0 Mbps now, 0 Mbps max
 2(p2): addr:aa:55:aa:55:00:0x
     config:     0
     state:      LIVE
     speed: 0 Mbps now, 0 Mbps max
 3(p3): addr:aa:55:aa:55:00:0x
     config:     0
     state:      LIVE
     speed: 0 Mbps now, 0 Mbps max
 LOCAL(br0): addr:aa:55:aa:55:00:0x
     config:     0
     state:      LIVE
     speed: 0 Mbps now, 0 Mbps max
])
AT_CHECK([ovs-ofctl -F OXM-OpenFlow15 -O OpenFlow15 -vwarn dump-ports-desc br0 2], [0], [stdout])
AT_CHECK([strip_xids < stdout | sed 's/00:0./00:0x/'], [0], [dnl
OFPST_PORT_DESC reply (OF1.5):
 2(p2): addr:aa:55:aa:55:00:0x
     config:     0
     state:      LIVE
     speed: 0 Mbps now, 0 Mbps max
])
OVS_VSWITCHD_STOP
AT_CLEANUP

dnl CHECK_QUEUE_STATS(label, option, format)
m4_define([CHECK_QUEUE_STATS], [
AT_SETUP([ofproto - queue stats - (OpenFlow $1)])
OVS_VSWITCHD_START

AT_CHECK([ovs-ofctl -O $2 queue-stats br0 | strip_xids], [0],
  [OFPST_QUEUE reply$3: 1 queues
  port LOCAL queue 0: bytes=?, pkts=?, errors=?, duration=?
])

AT_CHECK([ovs-ofctl -O $2 queue-stats br0 LOCAL | strip_xids], [0],
  [OFPST_QUEUE reply$3: 1 queues
  port LOCAL queue 0: bytes=?, pkts=?, errors=?, duration=?
])

AT_CHECK([ovs-ofctl -O $2 queue-stats br0 LOCAL 0 | strip_xids], [0],
  [OFPST_QUEUE reply$3: 1 queues
  port LOCAL queue 0: bytes=?, pkts=?, errors=?, duration=?
])

AT_CHECK([ovs-ofctl -O $2 queue-stats br0 ANY 0 | strip_xids], [0],
  [OFPST_QUEUE reply$3: 1 queues
  port LOCAL queue 0: bytes=?, pkts=?, errors=?, duration=?
])

AT_CHECK([ovs-ofctl -O $2 queue-stats br0 LOCAL 5 | strip_xids], [0],
  [OFPT_ERROR$3: OFPQOFC_BAD_QUEUE
OFPST_QUEUE request$3: port=LOCAL queue=5
])

AT_CHECK([ovs-ofctl -O $2 queue-stats br0 ANY 5 | strip_xids], [0],
  [OFPT_ERROR$3: OFPQOFC_BAD_QUEUE
OFPST_QUEUE request$3: port=ANY queue=5
])

AT_CHECK([ovs-ofctl -O $2 queue-stats br0 10 | strip_xids], [0],
  [OFPT_ERROR$3: OFPQOFC_BAD_PORT
OFPST_QUEUE request$3: port=10 queue=ALL
])
OVS_VSWITCHD_STOP
AT_CLEANUP
])
CHECK_QUEUE_STATS([1.0], [OpenFlow10], [])
CHECK_QUEUE_STATS([1.1], [OpenFlow11], [ (OF1.1)])
CHECK_QUEUE_STATS([1.2], [OpenFlow12], [ (OF1.2)])
CHECK_QUEUE_STATS([1.3], [OpenFlow13], [ (OF1.3)])
CHECK_QUEUE_STATS([1.4], [OpenFlow14], [ (OF1.4)])

dnl This is really bare-bones.
dnl It at least checks request and reply serialization and deserialization.
AT_SETUP([ofproto - queue configuration - (OpenFlow 1.0)])
OVS_VSWITCHD_START
add_of_ports br0 1 2
AT_CHECK([ovs-ofctl queue-get-config br0 1], [0], [stdout])
AT_CHECK([strip_xids < stdout], [0], [dnl
OFPT_QUEUE_GET_CONFIG_REPLY: port=1
queue 0:
])
AT_CHECK([ovs-ofctl queue-get-config br0], [0], [stdout])
AT_CHECK([strip_xids < stdout | sort], [0], [dnl
OFPT_QUEUE_GET_CONFIG_REPLY: port=1
OFPT_QUEUE_GET_CONFIG_REPLY: port=2
queue 0:
queue 0:
])
AT_CHECK([ovs-ofctl queue-get-config br0 10], [0],
  [OFPT_ERROR (xid=0x2): OFPQOFC_BAD_PORT
OFPT_QUEUE_GET_CONFIG_REQUEST (xid=0x2): port=10
])
OVS_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([ofproto - queue configuration - (OpenFlow 1.1)])
OVS_VSWITCHD_START
add_of_ports br0 1 2
AT_CHECK([ovs-ofctl -O OpenFlow11 queue-get-config br0 1], [0], [stdout])
AT_CHECK([strip_xids < stdout], [0], [dnl
OFPT_QUEUE_GET_CONFIG_REPLY (OF1.1): port=1
queue 0:
])
AT_CHECK([ovs-ofctl -O OpenFlow11 queue-get-config br0 10 | strip_xids], [0],
  [OFPT_ERROR (OF1.1): OFPQOFC_BAD_PORT
OFPT_QUEUE_GET_CONFIG_REQUEST (OF1.1): port=10
])
OVS_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([ofproto - queue configuration - (OpenFlow 1.2)])
OVS_VSWITCHD_START
add_of_ports br0 1 2
AT_CHECK([ovs-ofctl -O OpenFlow12 queue-get-config br0 1], [0], [stdout])
AT_CHECK([strip_xids < stdout], [0], [dnl
OFPT_QUEUE_GET_CONFIG_REPLY (OF1.2): port=1
queue 0:
])
AT_CHECK([ovs-ofctl -O OpenFlow12 queue-get-config br0 ANY], [0], [stdout])
AT_CHECK([strip_xids < stdout], [0], [dnl
OFPT_QUEUE_GET_CONFIG_REPLY (OF1.2): port=ANY
queue 0:
queue 0:
queue 0:
])
AT_CHECK([ovs-ofctl -O OpenFlow12 queue-get-config br0 10 | strip_xids], [0],
  [OFPT_ERROR (OF1.2): OFPQOFC_BAD_PORT
OFPT_QUEUE_GET_CONFIG_REQUEST (OF1.2): port=10
])
OVS_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([ofproto - queue configuration - (OpenFlow 1.4)])
OVS_VSWITCHD_START
add_of_ports br0 1 2

AT_CHECK([ovs-ofctl -O OpenFlow14 queue-get-config br0 any | strip_xids], [0],
  [OFPST_QUEUE_DESC reply (OF1.4): port=1
queue 0:
port=2
queue 0:
port=LOCAL
queue 0:
])

AT_CHECK([ovs-ofctl -O OpenFlow14 queue-get-config br0 1 | strip_xids], [0],
  [OFPST_QUEUE_DESC reply (OF1.4): port=1
queue 0:
])

AT_CHECK([ovs-ofctl -O OpenFlow14 queue-get-config br0 10 | strip_xids], [0],
  [OFPT_ERROR (OF1.4): OFPQOFC_BAD_PORT
OFPST_QUEUE_DESC request (OF1.4): port=10
])

AT_CHECK([ovs-ofctl -O OpenFlow14 queue-get-config br0 1 2 | strip_xids], [0],
  [OFPT_ERROR (OF1.4): OFPQOFC_BAD_QUEUE
OFPST_QUEUE_DESC request (OF1.4): port=1 queue=2
])
OVS_VSWITCHD_STOP
AT_CLEANUP

dnl This is really bare-bones.
dnl It at least checks request and reply serialization and deserialization.
dnl Actions definition listed in both supported formats (w/ actions=)
AT_SETUP([ofproto - del group (OpenFlow 1.0 extension)])
OVS_VSWITCHD_START
AT_DATA([groups.txt], [dnl
group_id=1233,type=select,selection_method=hash,bucket=output:10,bucket=output:11
group_id=1234,type=select,selection_method=hash,fields(eth_dst,ip_dst,tcp_dst),bucket=output:10,bucket=output:11
group_id=1235,type=all,bucket=actions=output:12,bucket=bucket_id:0,actions=output:10,bucket=bucket_id:1,actions=output:11
group_id=1236,type=select,selection_method=dp_hash,bucket=output:10,bucket=output:11
])
AT_CHECK([ovs-ofctl -O OpenFlow10 -vwarn add-groups br0 groups.txt])
AT_CHECK([ovs-ofctl -O OpenFlow10 -vwarn dump-groups br0 1234], [0], [stdout])
AT_CHECK([strip_xids < stdout], [0], [dnl
NXST_GROUP_DESC reply:
 group_id=1234,type=select,selection_method=hash,fields(eth_dst,ip_dst,tcp_dst),bucket=bucket_id:0,actions=output:10,bucket=bucket_id:1,actions=output:11
])
AT_CHECK([ovs-ofctl -O OpenFlow10 -vwarn del-groups br0 group_id=1234])
AT_CHECK([ovs-ofctl -O OpenFlow10 -vwarn dump-groups br0], [0], [stdout])
AT_CHECK([strip_xids < stdout | sort], [0], [dnl
 group_id=1233,type=select,selection_method=hash,bucket=bucket_id:0,actions=output:10,bucket=bucket_id:1,actions=output:11
 group_id=1235,type=all,bucket=bucket_id:2,actions=output:12,bucket=bucket_id:0,actions=output:10,bucket=bucket_id:1,actions=output:11
 group_id=1236,type=select,selection_method=dp_hash,bucket=bucket_id:0,actions=output:10,bucket=bucket_id:1,actions=output:11
NXST_GROUP_DESC reply:
])
AT_CHECK([ovs-ofctl -O OpenFlow10 -vwarn del-groups br0 group_id=1234])
AT_CHECK([ovs-ofctl -O OpenFlow10 -vwarn dump-groups br0], [0], [stdout])
AT_CHECK([strip_xids < stdout | sort], [0], [dnl
 group_id=1233,type=select,selection_method=hash,bucket=bucket_id:0,actions=output:10,bucket=bucket_id:1,actions=output:11
 group_id=1235,type=all,bucket=bucket_id:2,actions=output:12,bucket=bucket_id:0,actions=output:10,bucket=bucket_id:1,actions=output:11
 group_id=1236,type=select,selection_method=dp_hash,bucket=bucket_id:0,actions=output:10,bucket=bucket_id:1,actions=output:11
NXST_GROUP_DESC reply:
])
AT_CHECK([ovs-ofctl -O OpenFlow10 -vwarn del-groups br0], [0])
AT_CHECK([ovs-ofctl -O OpenFlow10 -vwarn dump-groups br0], [0], [stdout])
AT_CHECK([strip_xids < stdout], [0], [dnl
NXST_GROUP_DESC reply:
])
OVS_VSWITCHD_STOP
AT_CLEANUP

dnl This is really bare-bones.
dnl It at least checks request and reply serialization and deserialization.
dnl Actions definition listed in both supported formats (w/ actions=)
AT_SETUP([ofproto - del group (OpenFlow 1.1)])
OVS_VSWITCHD_START
AT_DATA([groups.txt], [dnl
group_id=1234,type=all,bucket=output:10
group_id=1235,type=all,bucket=actions=output:10
])
AT_CHECK([ovs-ofctl -O OpenFlow11 -vwarn add-groups br0 groups.txt])
AT_CHECK([ovs-ofctl -O OpenFlow11 -vwarn dump-groups br0 ], [0], [stdout])
AT_CHECK([strip_xids < stdout | sort], [0], [dnl
 group_id=1234,type=all,bucket=actions=output:10
 group_id=1235,type=all,bucket=actions=output:10
OFPST_GROUP_DESC reply (OF1.1):
])
AT_CHECK([ovs-ofctl -O OpenFlow11 -vwarn del-groups br0 group_id=1234])
AT_CHECK([ovs-ofctl -O OpenFlow11 -vwarn dump-groups br0], [0], [stdout])
AT_CHECK([strip_xids < stdout], [0], [dnl
OFPST_GROUP_DESC reply (OF1.1):
 group_id=1235,type=all,bucket=actions=output:10
])
AT_CHECK([ovs-ofctl -O OpenFlow11 -vwarn del-groups br0 group_id=1234])
AT_CHECK([ovs-ofctl -O OpenFlow11 -vwarn dump-groups br0], [0], [stdout])
AT_CHECK([strip_xids < stdout], [0], [dnl
OFPST_GROUP_DESC reply (OF1.1):
 group_id=1235,type=all,bucket=actions=output:10
])
AT_CHECK([ovs-ofctl -O OpenFlow11 -vwarn del-groups br0], [0])
AT_CHECK([ovs-ofctl -O OpenFlow11 -vwarn dump-groups br0], [0], [stdout])
AT_CHECK([strip_xids < stdout], [0], [dnl
OFPST_GROUP_DESC reply (OF1.1):
])

# Negative test.
AT_CHECK([ovs-ofctl -O OpenFlow11 -vwarn del-groups br0 group_id=0xfffffff0],
  [1], [], [ovs-ofctl: invalid group id 4294967280
])
OVS_VSWITCHD_STOP
AT_CLEANUP

dnl This is really bare-bones.
dnl It at least checks request and reply serialization and deserialization.
dnl Actions definition listed in both supported formats (w/ actions=)
AT_SETUP([ofproto - add indirect group])
OVS_VSWITCHD_START
dnl indirect group must have exactly one bucket
AT_DATA([stderr], [dnl
OFPT_ERROR (OF1.1) (xid=0x2): OFPGMFC_INVALID_GROUP
OFPT_GROUP_MOD (OF1.1) (xid=0x2): ***decode error: OFPGMFC_INVALID_GROUP***
])
AT_CHECK([ovs-ofctl -O OpenFlow11 -vwarn add-group br0 'group_id=1234,type=indirect'], [1], , [stderr])
AT_CHECK([ovs-ofctl -O OpenFlow11 -vwarn add-group br0 'group_id=1235,type=indirect,bucket=output:10'])
AT_CHECK([ovs-ofctl -O OpenFlow11 -vwarn add-group br0 'group_id=1236,type=indirect,bucket=output:10,bucket=output:11'], [1], , [stderr])
OVS_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([ofproto - group mod with mod and add_or_mod command])
OVS_VSWITCHD_START
dnl Check that mod-group for non-existing group fails without --may-create
AT_DATA([stderr], [dnl
OFPT_ERROR (OF1.3) (xid=0x2): OFPGMFC_UNKNOWN_GROUP
OFPT_GROUP_MOD (OF1.3) (xid=0x2):
 MOD group_id=1234,type=indirect,bucket=actions=output:2
])
AT_CHECK([ovs-ofctl -O OpenFlow13 -vwarn mod-group br0 'group_id=1234,type=indirect,bucket=actions=2'], [1], , [stderr])
dnl Check that mod-group for non-existing group succeeds with --may-create
AT_CHECK([ovs-ofctl -O OpenFlow13 -vwarn --may-create mod-group br0 'group_id=1234,type=indirect,bucket=actions=2'])
AT_CHECK([ovs-ofctl -O OpenFlow13 -vwarn dump-groups br0], [0], [stdout])
AT_CHECK([strip_xids < stdout], [0], [dnl
OFPST_GROUP_DESC reply (OF1.3):
 group_id=1234,type=indirect,bucket=actions=output:2
])
dnl Check that mod-group for existing group succeeds with --may-create
AT_CHECK([ovs-ofctl -O OpenFlow13 -vwarn --may-create mod-group br0 'group_id=1234,type=indirect,bucket=actions=3'])
AT_CHECK([ovs-ofctl -O OpenFlow13 -vwarn dump-groups br0], [0], [stdout])
AT_CHECK([strip_xids < stdout], [0], [dnl
OFPST_GROUP_DESC reply (OF1.3):
 group_id=1234,type=indirect,bucket=actions=output:3
])
OVS_VSWITCHD_STOP
AT_CLEANUP

dnl This is really bare-bones.
dnl It at least checks request and reply serialization and deserialization.
dnl Actions definition listed in both supported formats (w/ actions=)
AT_SETUP([ofproto - del group (OpenFlow 1.5)])
OVS_VSWITCHD_START
AT_DATA([groups.txt], [dnl
group_id=1233,type=select,selection_method=hash,bucket=output:10,bucket=output:11
group_id=1234,type=select,selection_method=hash,fields(eth_dst,ip_dst,tcp_dst),bucket=output:10,bucket=output:11
group_id=1235,type=all,bucket=actions=output:12,bucket=bucket_id:0,actions=output:10,bucket=bucket_id:1,actions=output:11
group_id=1236,type=select,selection_method=dp_hash,bucket=output:10,bucket=output:11
])
AT_CHECK([ovs-ofctl -O OpenFlow15 -vwarn add-groups br0 groups.txt])
AT_CHECK([ovs-ofctl -F OXM-OpenFlow15 -O OpenFlow15 -vwarn dump-groups br0 1234], [0], [stdout])
AT_CHECK([strip_xids < stdout], [0], [dnl
OFPST_GROUP_DESC reply (OF1.5):
 group_id=1234,type=select,selection_method=hash,fields(eth_dst,ip_dst,tcp_dst),bucket=bucket_id:0,actions=output:10,bucket=bucket_id:1,actions=output:11
])
AT_CHECK([ovs-ofctl -O OpenFlow15 -vwarn del-groups br0 group_id=1234])
AT_CHECK([ovs-ofctl -O OpenFlow15 -vwarn dump-groups br0], [0], [stdout])
AT_CHECK([strip_xids < stdout | sort], [0], [dnl
 group_id=1233,type=select,selection_method=hash,bucket=bucket_id:0,actions=output:10,bucket=bucket_id:1,actions=output:11
 group_id=1235,type=all,bucket=bucket_id:2,actions=output:12,bucket=bucket_id:0,actions=output:10,bucket=bucket_id:1,actions=output:11
 group_id=1236,type=select,selection_method=dp_hash,bucket=bucket_id:0,actions=output:10,bucket=bucket_id:1,actions=output:11
OFPST_GROUP_DESC reply (OF1.5):
])
AT_CHECK([ovs-ofctl -O OpenFlow15 -vwarn del-groups br0 group_id=1234])
AT_CHECK([ovs-ofctl -O OpenFlow15 -vwarn dump-groups br0], [0], [stdout])
AT_CHECK([strip_xids < stdout | sort], [0], [dnl
 group_id=1233,type=select,selection_method=hash,bucket=bucket_id:0,actions=output:10,bucket=bucket_id:1,actions=output:11
 group_id=1235,type=all,bucket=bucket_id:2,actions=output:12,bucket=bucket_id:0,actions=output:10,bucket=bucket_id:1,actions=output:11
 group_id=1236,type=select,selection_method=dp_hash,bucket=bucket_id:0,actions=output:10,bucket=bucket_id:1,actions=output:11
OFPST_GROUP_DESC reply (OF1.5):
])
AT_CHECK([ovs-ofctl -O OpenFlow15 -vwarn del-groups br0], [0])
AT_CHECK([ovs-ofctl -O OpenFlow15 -vwarn dump-groups br0], [0], [stdout])
AT_CHECK([strip_xids < stdout], [0], [dnl
OFPST_GROUP_DESC reply (OF1.5):
])
OVS_VSWITCHD_STOP
AT_CLEANUP

dnl This is really bare-bones.
dnl It at least checks request and reply serialization and deserialization.
AT_SETUP([ofproto - del group deletes flows])
OVS_VSWITCHD_START
AT_DATA([groups.txt], [dnl
group_id=1234,type=all,bucket=output:10
group_id=1235,type=all,bucket=output:10
])
AT_CHECK([ovs-ofctl -O OpenFlow11 -vwarn add-groups br0 groups.txt])
AT_DATA([flows.txt], [dnl
tcp actions=group:1234
table=2 udp actions=group:1235
])
AT_CHECK([ovs-ofctl -O OpenFlow11 -vwarn add-flows br0 flows.txt])
AT_CHECK([ovs-ofctl -O OpenFlow11 -vwarn dump-flows br0 | ofctl_strip | sort],
[0], [dnl
 table=2, udp actions=group:1235
 tcp actions=group:1234
OFPST_FLOW reply (OF1.1):
])
AT_CHECK([ovs-ofctl -O OpenFlow11 -vwarn del-groups br0 group_id=1234])
AT_CHECK([ovs-ofctl -O OpenFlow11 -vwarn dump-flows br0 | ofctl_strip | sort],
[0], [dnl
 table=2, udp actions=group:1235
OFPST_FLOW reply (OF1.1):
])
AT_CHECK([ovs-ofctl -O OpenFlow11 -vwarn del-groups br0 group_id=1234])
AT_CHECK([ovs-ofctl -O OpenFlow11 -vwarn dump-flows br0 | ofctl_strip | sort],
[0], [dnl
 table=2, udp actions=group:1235
OFPST_FLOW reply (OF1.1):
])
AT_CHECK([ovs-ofctl -O OpenFlow11 -vwarn del-groups br0])
AT_CHECK([ovs-ofctl -O OpenFlow11 -vwarn dump-flows br0 | ofctl_strip | sort],
[0], [dnl
OFPST_FLOW reply (OF1.1):
])
OVS_VSWITCHD_STOP
AT_CLEANUP

dnl This is really bare-bones.
dnl It at least checks request and reply serialization and deserialization.
dnl Actions definition listed in both supported formats (w/ actions=)
AT_SETUP([ofproto - insert group buckets])
OVS_VSWITCHD_START
# Add group with no buckets.
AT_DATA([groups.txt], [dnl
group_id=1234,type=all
])
AT_CHECK([ovs-ofctl -O OpenFlow15 -vwarn add-groups br0 groups.txt])
AT_CHECK([ovs-ofctl -F OXM-OpenFlow15 -O OpenFlow15 -vwarn dump-groups br0 1234], [0], [stdout])
AT_CHECK([strip_xids < stdout], [0], [dnl
OFPST_GROUP_DESC reply (OF1.5):
 group_id=1234,type=all
])

# Add two buckets, using "last".
AT_CHECK([ovs-ofctl -O OpenFlow15 -vwarn insert-buckets br0 group_id=1234,command_bucket_id=last,bucket=bucket_id:10,actions=output:10,bucket=bucket_id:11,actions=output:11])
AT_CHECK([ovs-ofctl -F OXM-OpenFlow15 -O OpenFlow15 -vwarn dump-groups br0 1234], [0], [stdout])
AT_CHECK([strip_xids < stdout], [0], [dnl
OFPST_GROUP_DESC reply (OF1.5):
 group_id=1234,type=all,bucket=bucket_id:10,actions=output:10,bucket=bucket_id:11,actions=output:11
])

# Start over again, then add two buckets using "first".
AT_CHECK([ovs-ofctl -O OpenFlow15 --strict del-groups br0 group_id=1234])
AT_CHECK([ovs-ofctl -O OpenFlow15 -vwarn add-group br0 group_id=1234,type=all])
AT_CHECK([ovs-ofctl -O OpenFlow15 -vwarn insert-buckets br0 group_id=1234,command_bucket_id=first,bucket=bucket_id:10,actions=output:10,bucket=bucket_id:11,actions=output:11])
AT_CHECK([ovs-ofctl -F OXM-OpenFlow15 -O OpenFlow15 -vwarn dump-groups br0 1234], [0], [stdout])
AT_CHECK([strip_xids < stdout], [0], [dnl
OFPST_GROUP_DESC reply (OF1.5):
 group_id=1234,type=all,bucket=bucket_id:10,actions=output:10,bucket=bucket_id:11,actions=output:11
])

# Add two more buckets before the existing ones.
AT_CHECK([ovs-ofctl -O OpenFlow15 -vwarn insert-buckets br0 group_id=1234,command_bucket_id=first,bucket=bucket_id:0,actions=output:0,bucket=bucket_id:1,actions=output:1])
AT_CHECK([ovs-ofctl -O OpenFlow15 -vwarn dump-groups br0], [0], [stdout])
AT_CHECK([strip_xids < stdout], [0], [dnl
OFPST_GROUP_DESC reply (OF1.5):
 group_id=1234,type=all,bucket=bucket_id:0,actions=output:0,bucket=bucket_id:1,actions=output:1,bucket=bucket_id:10,actions=output:10,bucket=bucket_id:11,actions=output:11
])

# Add another bucket at the end.
AT_CHECK([ovs-ofctl -O OpenFlow15 -vwarn insert-buckets br0 group_id=1234,command_bucket_id=last,bucket=bucket_id:14,actions=output:14,bucket=bucket_id:15,actions=output:15])
AT_CHECK([ovs-ofctl -O OpenFlow15 -vwarn dump-groups br0], [0], [stdout])
AT_CHECK([strip_xids < stdout], [0], [dnl
OFPST_GROUP_DESC reply (OF1.5):
 group_id=1234,type=all,bucket=bucket_id:0,actions=output:0,bucket=bucket_id:1,actions=output:1,bucket=bucket_id:10,actions=output:10,bucket=bucket_id:11,actions=output:11,bucket=bucket_id:14,actions=output:14,bucket=bucket_id:15,actions=output:15
])

# Verify that duplicate bucket IDs are rejected.
AT_CHECK([ovs-ofctl -O OpenFlow15 -vwarn insert-buckets br0 group_id=1234,command_bucket_id=last,bucket=bucket_id:14,actions=output:14,bucket=bucket_id:15,actions=output:15], [1], [], [stderr])
AT_CHECK([strip_xids < stderr | sed '/truncated/,$d'], [0], [dnl
OFPT_ERROR (OF1.5): OFPGMFC_BUCKET_EXISTS
OFPT_GROUP_MOD (OF1.5):
 INSERT_BUCKET command_bucket_id:last,group_id=1234,bucket=bucket_id:14,actions=output:14,bucket=bucket_id:15,actions=output:15
])


# Add another bucket just before bucket 15.
AT_CHECK([ovs-ofctl -O OpenFlow15 -vwarn insert-buckets br0 group_id=1234,command_bucket_id=15])
AT_CHECK([ovs-ofctl -O OpenFlow15 -vwarn dump-groups br0], [0], [stdout])
AT_CHECK([strip_xids < stdout], [0], [dnl
OFPST_GROUP_DESC reply (OF1.5):
 group_id=1234,type=all,bucket=bucket_id:0,actions=output:0,bucket=bucket_id:1,actions=output:1,bucket=bucket_id:10,actions=output:10,bucket=bucket_id:11,actions=output:11,bucket=bucket_id:14,actions=output:14,bucket=bucket_id:15,actions=output:15
])

# Add two more buckets just before bucket 11,
# getting the command from a file.
AT_DATA([buckets.txt], [dnl
group_id=1234,command_bucket_id=11,bucket=bucket_id:12,actions=output:12,bucket=bucket_id:13,actions=output:13
])
AT_CHECK([ovs-ofctl -O OpenFlow15 -vwarn insert-buckets br0 - < buckets.txt])
AT_CHECK([ovs-ofctl -O OpenFlow15 -vwarn dump-groups br0], [0], [stdout])
AT_CHECK([strip_xids < stdout], [0], [dnl
OFPST_GROUP_DESC reply (OF1.5):
 group_id=1234,type=all,bucket=bucket_id:0,actions=output:0,bucket=bucket_id:1,actions=output:1,bucket=bucket_id:10,actions=output:10,bucket=bucket_id:11,actions=output:11,bucket=bucket_id:12,actions=output:12,bucket=bucket_id:13,actions=output:13,bucket=bucket_id:14,actions=output:14,bucket=bucket_id:15,actions=output:15
])

# Add yet two more buckets.
AT_CHECK([ovs-ofctl -O OpenFlow15 -vwarn insert-buckets br0 group_id=1234,command_bucket_id=15,bucket=bucket_id:20,actions=output:20,bucket=bucket_id:21,actions=output:21])
AT_CHECK([ovs-ofctl -O OpenFlow15 -vwarn dump-groups br0], [0], [stdout])
AT_CHECK([strip_xids < stdout], [0], [dnl
OFPST_GROUP_DESC reply (OF1.5):
 group_id=1234,type=all,bucket=bucket_id:0,actions=output:0,bucket=bucket_id:1,actions=output:1,bucket=bucket_id:10,actions=output:10,bucket=bucket_id:11,actions=output:11,bucket=bucket_id:12,actions=output:12,bucket=bucket_id:13,actions=output:13,bucket=bucket_id:14,actions=output:14,bucket=bucket_id:15,actions=output:15,bucket=bucket_id:20,actions=output:20,bucket=bucket_id:21,actions=output:21
])

# Delete groups.
AT_CHECK([ovs-ofctl -O OpenFlow15 del-groups br0])

# Add "fast_failover" group, then insert a bucket into it and make
# sure that the type of the group doesn't change.  (There was a bug
# that caused this to happen.)
AT_CHECK([ovs-ofctl -O OpenFlow15 -vwarn add-group br0 group_id=1234,type=ff])
AT_CHECK([ovs-ofctl -O OpenFlow15 -vwarn dump-groups br0], [0], [stdout])
AT_CHECK([strip_xids < stdout], [0], [dnl
OFPST_GROUP_DESC reply (OF1.5):
 group_id=1234,type=ff
])
AT_CHECK([ovs-ofctl -O OpenFlow15 -vwarn insert-buckets br0 group_id=1234,command_bucket_id=first,bucket=bucket_id:20,actions=output:20,bucket=bucket_id:21,actions=output:21])
AT_CHECK([ovs-ofctl -O OpenFlow15 -vwarn dump-groups br0], [0], [stdout])
AT_CHECK([strip_xids < stdout], [0], [dnl
OFPST_GROUP_DESC reply (OF1.5):
 group_id=1234,type=ff,bucket=bucket_id:20,actions=output:20,bucket=bucket_id:21,actions=output:21
])

# Negative tests.
AT_CHECK([ovs-ofctl -O OpenFlow15 -vwarn insert-buckets br0 group_id=1234,command_bucket_id=123,type=indirect,bucket=bucket_id:0,actions=output:0,bucket=bucket_id:1,actions=output:1], [1], [],
  [ovs-ofctl: type is not needed
])
AT_CHECK([ovs-ofctl -O OpenFlow15 -vwarn insert-buckets br0 group_id=1234,command_bucket_id=123,selection_method=dp_hash,type=indirect,bucket=bucket_id:0,actions=output:0,bucket=bucket_id:1,actions=output:1], [1], [],
  [ovs-ofctl: selection method is not needed
])
AT_CHECK([ovs-ofctl -O OpenFlow15 -vwarn insert-buckets br0 group_id=1234,command_bucket_id=0xffffff01,bucket=bucket_id:0,actions=output:0,bucket=bucket_id:1,actions=output:1], [1], [],
  [ovs-ofctl: invalid command bucket id 4294967041
])
AT_CHECK([ovs-ofctl -O OpenFlow11 -vwarn insert-buckets br0 group_id=1234,command_bucket_id=first,bucket=bucket_id:0,actions=output:0,bucket=bucket_id:1,actions=output:1], [1], [],
  [ovs-ofctl: insert-bucket needs OpenFlow 1.5 or later ('-O OpenFlow15')
])

# Verify insert-buckets command to insert bucket with weight value for select group.
AT_CHECK([ovs-ofctl -O OpenFlow15 --strict del-groups br0 group_id=1234])
AT_DATA([groups.txt], [dnl
group_id=1234,type=select,selection_method=hash,bucket=bucket_id=1,weight:100,output:11
])
AT_CHECK([ovs-ofctl -O OpenFlow15 -vwarn add-groups br0 groups.txt])
AT_CHECK([ovs-ofctl -O OpenFlow15 insert-buckets br0 group_id=1234,command_bucket_id=last,bucket=bucket_id=2,weight=100,actions=output:11])
AT_CHECK([ovs-ofctl -O OpenFlow15 -vwarn dump-groups br0], [0], [stdout])
AT_CHECK([strip_xids < stdout], [0], [dnl
OFPST_GROUP_DESC reply (OF1.5):
 group_id=1234,type=select,selection_method=hash,bucket=bucket_id:1,weight:100,actions=output:11,bucket=bucket_id:2,weight:100,actions=output:11
])

OVS_VSWITCHD_STOP
AT_CLEANUP

dnl This is really bare-bones.
dnl It at least checks request and reply serialization and deserialization.
dnl Actions definition listed in both supported formats (w/ actions=)
AT_SETUP([ofproto - remove group buckets])
OVS_VSWITCHD_START
AT_DATA([groups.txt], [dnl
group_id=1234,type=all,bucket=bucket_id:10,actions=output:10,bucket=bucket_id:11,actions=output:11,bucket=bucket_id:12,actions=output:12,bucket=bucket_id:13,actions=output:13,bucket=bucket_id:14,actions=output:14,bucket=bucket_id:15,actions=output:15,bucket=bucket_id:16,actions=output:16
])
AT_CHECK([ovs-ofctl -O OpenFlow15 -vwarn add-groups br0 groups.txt])
AT_CHECK([ovs-ofctl -F OXM-OpenFlow15 -O OpenFlow15 -vwarn dump-groups br0 1234], [0], [stdout])
AT_CHECK([strip_xids < stdout], [0], [dnl
OFPST_GROUP_DESC reply (OF1.5):
 group_id=1234,type=all,bucket=bucket_id:10,actions=output:10,bucket=bucket_id:11,actions=output:11,bucket=bucket_id:12,actions=output:12,bucket=bucket_id:13,actions=output:13,bucket=bucket_id:14,actions=output:14,bucket=bucket_id:15,actions=output:15,bucket=bucket_id:16,actions=output:16
])
AT_CHECK([ovs-ofctl -O OpenFlow15 -vwarn remove-buckets br0 group_id=1234,command_bucket_id=first])
AT_CHECK([ovs-ofctl -O OpenFlow15 -vwarn dump-groups br0], [0], [stdout])
AT_CHECK([strip_xids < stdout], [0], [dnl
OFPST_GROUP_DESC reply (OF1.5):
 group_id=1234,type=all,bucket=bucket_id:11,actions=output:11,bucket=bucket_id:12,actions=output:12,bucket=bucket_id:13,actions=output:13,bucket=bucket_id:14,actions=output:14,bucket=bucket_id:15,actions=output:15,bucket=bucket_id:16,actions=output:16
])
AT_CHECK([ovs-ofctl -O OpenFlow15 -vwarn remove-buckets br0 group_id=1234,command_bucket_id=last])
AT_CHECK([ovs-ofctl -O OpenFlow15 -vwarn dump-groups br0], [0], [stdout])
AT_CHECK([strip_xids < stdout], [0], [dnl
OFPST_GROUP_DESC reply (OF1.5):
 group_id=1234,type=all,bucket=bucket_id:11,actions=output:11,bucket=bucket_id:12,actions=output:12,bucket=bucket_id:13,actions=output:13,bucket=bucket_id:14,actions=output:14,bucket=bucket_id:15,actions=output:15
])
AT_CHECK([ovs-ofctl -O OpenFlow15 -vwarn remove-buckets br0 group_id=1234,command_bucket_id=13])
AT_CHECK([ovs-ofctl -O OpenFlow15 -vwarn dump-groups br0], [0], [stdout])
AT_CHECK([strip_xids < stdout], [0], [dnl
OFPST_GROUP_DESC reply (OF1.5):
 group_id=1234,type=all,bucket=bucket_id:11,actions=output:11,bucket=bucket_id:12,actions=output:12,bucket=bucket_id:14,actions=output:14,bucket=bucket_id:15,actions=output:15
])
AT_DATA([buckets.txt], [dnl
group_id=1234
])
AT_CHECK([ovs-ofctl -O OpenFlow15 -vwarn remove-buckets br0 - < buckets.txt])
AT_CHECK([ovs-ofctl -O OpenFlow15 -vwarn dump-groups br0], [0], [stdout])
AT_CHECK([strip_xids < stdout], [0], [dnl
OFPST_GROUP_DESC reply (OF1.5):
 group_id=1234,type=all
])
AT_CHECK([ovs-ofctl -O OpenFlow15 -vwarn remove-buckets br0 group_id=1234,command_bucket_id=first])
AT_CHECK([ovs-ofctl -O OpenFlow15 -vwarn remove-buckets br0 group_id=1234,command_bucket_id=last])
AT_CHECK([ovs-ofctl -O OpenFlow15 -vwarn remove-buckets br0 group_id=1234,command_bucket_id=all])
AT_CHECK([ovs-ofctl -O OpenFlow15 -vwarn remove-buckets br0 group_id=1234,command_bucket_id=1], [1], [], [stderr])
AT_CHECK([ofctl_strip < stderr], [0], [dnl
OFPT_ERROR (OF1.5): OFPGMFC_UNKNOWN_BUCKET
OFPT_GROUP_MOD (OF1.5):
 REMOVE_BUCKET command_bucket_id:1,group_id=1234
])
# Negative test.
AT_CHECK([ovs-ofctl -O OpenFlow11 -vwarn remove-buckets br0 group_id=1234,command_bucket_id=last], [1], [],
  [ovs-ofctl: none of the usable flow formats (OpenFlow10,NXM,OXM-OpenFlow15) is among the allowed flow formats (OpenFlow11)
])
OVS_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([ofproto - bundle del group (OpenFlow 1.3)])
OVS_VSWITCHD_START
AT_DATA([groups.txt], [dnl
group_id=1234,type=all,bucket=output:10
group_id=1235,type=all,bucket=actions=output:10
])
AT_CHECK([ovs-ofctl --bundle -O OpenFlow13 -vwarn add-groups br0 groups.txt])
AT_CHECK([ovs-ofctl -O OpenFlow13 -vwarn dump-groups br0 ], [0], [stdout])
AT_CHECK([strip_xids < stdout | sort], [0], [dnl
 group_id=1234,type=all,bucket=actions=output:10
 group_id=1235,type=all,bucket=actions=output:10
OFPST_GROUP_DESC reply (OF1.3):
])
AT_CHECK([ovs-ofctl --bundle -O OpenFlow13 -vwarn del-groups br0 group_id=1234])
AT_CHECK([ovs-ofctl -O OpenFlow13 -vwarn dump-groups br0], [0], [stdout])
AT_CHECK([strip_xids < stdout], [0], [dnl
OFPST_GROUP_DESC reply (OF1.3):
 group_id=1235,type=all,bucket=actions=output:10
])
AT_CHECK([ovs-ofctl --bundle -O OpenFlow13 -vwarn del-groups br0 group_id=1234])
AT_CHECK([ovs-ofctl -O OpenFlow13 -vwarn dump-groups br0], [0], [stdout])
AT_CHECK([strip_xids < stdout], [0], [dnl
OFPST_GROUP_DESC reply (OF1.3):
 group_id=1235,type=all,bucket=actions=output:10
])
AT_CHECK([ovs-ofctl --bundle -O OpenFlow13 -vwarn del-groups br0], [0])
AT_CHECK([ovs-ofctl -O OpenFlow13 -vwarn dump-groups br0], [0], [stdout])
AT_CHECK([strip_xids < stdout], [0], [dnl
OFPST_GROUP_DESC reply (OF1.3):
])

# Negative test.
AT_CHECK([ovs-ofctl --bundle -O OpenFlow13 -vwarn del-groups br0 group_id=0xfffffff0],
  [1], [], [ovs-ofctl: invalid group id 4294967280
])
OVS_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([ofproto - bundle add indirect group])
OVS_VSWITCHD_START
dnl indirect group must have exactly one bucket
AT_DATA([stderr], [dnl
OFPT_ERROR (OF1.4) (xid=0x2): OFPGMFC_INVALID_GROUP
OFPT_BUNDLE_ADD_MESSAGE (OF1.4) (xid=0x2):
 bundle_id=0 flags=atomic ordered
OFPT_GROUP_MOD (OF1.4) (xid=0x2): ***decode error: OFPGMFC_INVALID_GROUP***
])
AT_CHECK([ovs-ofctl --bundle -vwarn add-group br0 'group_id=1234,type=indirect'], [1], , [stderr])
AT_CHECK([ovs-ofctl --bundle -vwarn add-group br0 'group_id=1235,type=indirect,bucket=output:10'])
AT_CHECK([ovs-ofctl --bundle -vwarn add-group br0 'group_id=1236,type=indirect,bucket=output:10,bucket=output:11'], [1], , [stderr])
OVS_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([ofproto - bundle group mod with mod and add_or_mod command])
OVS_VSWITCHD_START
dnl Check that mod-group for non-existing group fails without --may-create
AT_DATA([stderr], [dnl
OFPT_ERROR (OF1.4) (xid=0x2): OFPGMFC_UNKNOWN_GROUP
OFPT_GROUP_MOD (OF1.4) (xid=0x2):
 MOD group_id=1234,type=indirect,bucket=actions=output:2
])
AT_CHECK([ovs-ofctl --bundle -vwarn mod-group br0 'group_id=1234,type=indirect,bucket=actions=2'], [1], , [stderr])
dnl Check that mod-group for non-existing group succeeds with --may-create
AT_CHECK([ovs-ofctl --bundle -vwarn --may-create mod-group br0 'group_id=1234,type=indirect,bucket=actions=2'])
AT_CHECK([ovs-ofctl -O OpenFlow14 -vwarn dump-groups br0], [0], [stdout])
AT_CHECK([strip_xids < stdout], [0], [dnl
OFPST_GROUP_DESC reply (OF1.4):
 group_id=1234,type=indirect,bucket=actions=output:2
])
dnl Check that mod-group for existing group succeeds with --may-create
AT_CHECK([ovs-ofctl --bundle -vwarn --may-create mod-group br0 'group_id=1234,type=indirect,bucket=actions=3'])
AT_CHECK([ovs-ofctl -O OpenFlow14 -vwarn dump-groups br0], [0], [stdout])
AT_CHECK([strip_xids < stdout], [0], [dnl
OFPST_GROUP_DESC reply (OF1.4):
 group_id=1234,type=indirect,bucket=actions=output:3
])
OVS_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([ofproto - bundle del group (OpenFlow 1.5)])
OVS_VSWITCHD_START
AT_DATA([groups.txt], [dnl
group_id=1233,type=select,selection_method=hash,bucket=output:10,bucket=output:11
group_id=1234,type=select,selection_method=hash,fields(eth_dst,ip_dst,tcp_dst),bucket=output:10,bucket=output:11
group_id=1235,type=all,bucket=actions=output:12,bucket=bucket_id:0,actions=output:10,bucket=bucket_id:1,actions=output:11
])
AT_CHECK([ovs-ofctl --bundle -O OpenFlow15 -vwarn add-groups br0 groups.txt])
AT_CHECK([ovs-ofctl -F OXM-OpenFlow15 -O OpenFlow15 -vwarn dump-groups br0 1234], [0], [stdout])
AT_CHECK([strip_xids < stdout], [0], [dnl
OFPST_GROUP_DESC reply (OF1.5):
 group_id=1234,type=select,selection_method=hash,fields(eth_dst,ip_dst,tcp_dst),bucket=bucket_id:0,actions=output:10,bucket=bucket_id:1,actions=output:11
])
AT_CHECK([ovs-ofctl --bundle -O OpenFlow15 -vwarn del-groups br0 group_id=1234])
AT_CHECK([ovs-ofctl -O OpenFlow15 -vwarn dump-groups br0], [0], [stdout])
AT_CHECK([strip_xids < stdout | sort], [0], [dnl
 group_id=1233,type=select,selection_method=hash,bucket=bucket_id:0,actions=output:10,bucket=bucket_id:1,actions=output:11
 group_id=1235,type=all,bucket=bucket_id:2,actions=output:12,bucket=bucket_id:0,actions=output:10,bucket=bucket_id:1,actions=output:11
OFPST_GROUP_DESC reply (OF1.5):
])
AT_CHECK([ovs-ofctl --bundle -O OpenFlow15 -vwarn del-groups br0 group_id=1234])
AT_CHECK([ovs-ofctl -O OpenFlow15 -vwarn dump-groups br0], [0], [stdout])
AT_CHECK([strip_xids < stdout | sort], [0], [dnl
 group_id=1233,type=select,selection_method=hash,bucket=bucket_id:0,actions=output:10,bucket=bucket_id:1,actions=output:11
 group_id=1235,type=all,bucket=bucket_id:2,actions=output:12,bucket=bucket_id:0,actions=output:10,bucket=bucket_id:1,actions=output:11
OFPST_GROUP_DESC reply (OF1.5):
])
AT_CHECK([ovs-ofctl --bundle -O OpenFlow15 -vwarn del-groups br0], [0])
AT_CHECK([ovs-ofctl -O OpenFlow15 -vwarn dump-groups br0], [0], [stdout])
AT_CHECK([strip_xids < stdout], [0], [dnl
OFPST_GROUP_DESC reply (OF1.5):
])
OVS_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([ofproto - bundle del group deletes flows])
OVS_VSWITCHD_START
AT_DATA([groups.txt], [dnl
group_id=1234,type=all,bucket=output:10
group_id=1235,type=all,bucket=output:10
])
AT_CHECK([ovs-ofctl --bundle -vwarn add-groups br0 groups.txt])
AT_DATA([flows.txt], [dnl
tcp actions=group:1234
table=2 udp actions=group:1235
])
AT_CHECK([ovs-ofctl --bundle -vwarn add-flows br0 flows.txt])
AT_CHECK([ovs-ofctl -O OpenFlow14 -vwarn dump-flows br0 | ofctl_strip | sort],
[0], [dnl
 table=2, udp actions=group:1235
 tcp actions=group:1234
OFPST_FLOW reply (OF1.4):
])
AT_CHECK([ovs-ofctl --bundle -vwarn del-groups br0 group_id=1234])
AT_CHECK([ovs-ofctl -O OpenFlow14 -vwarn dump-flows br0 | ofctl_strip | sort],
[0], [dnl
 table=2, udp actions=group:1235
OFPST_FLOW reply (OF1.4):
])
AT_CHECK([ovs-ofctl --bundle -vwarn del-groups br0 group_id=1234])
AT_CHECK([ovs-ofctl -O OpenFlow14 -vwarn dump-flows br0 | ofctl_strip | sort],
[0], [dnl
 table=2, udp actions=group:1235
OFPST_FLOW reply (OF1.4):
])
AT_CHECK([ovs-ofctl --bundle -vwarn del-groups br0])
AT_CHECK([ovs-ofctl -O OpenFlow14 -vwarn dump-flows br0 | ofctl_strip | sort],
[0], [dnl
OFPST_FLOW reply (OF1.4):
])
OVS_VSWITCHD_STOP
AT_CLEANUP

dnl This is really bare-bones.
dnl It at least checks request and reply serialization and deserialization.
dnl Actions definition listed in both supported formats (w/ actions=)
AT_SETUP([ofproto - bundle insert group buckets])
OVS_VSWITCHD_START
# Add group with no buckets.
AT_DATA([groups.txt], [dnl
group_id=1234,type=all
])
AT_CHECK([ovs-ofctl --bundle -O OpenFlow15 -vwarn add-groups br0 groups.txt])
AT_CHECK([ovs-ofctl -F OXM-OpenFlow15 -O OpenFlow15 -vwarn dump-groups br0 1234], [0], [stdout])
AT_CHECK([strip_xids < stdout], [0], [dnl
OFPST_GROUP_DESC reply (OF1.5):
 group_id=1234,type=all
])

# Add two buckets, using "last".
AT_CHECK([ovs-ofctl --bundle -O OpenFlow15 -vwarn insert-buckets br0 group_id=1234,command_bucket_id=last,bucket=bucket_id:10,actions=output:10,bucket=bucket_id:11,actions=output:11])
AT_CHECK([ovs-ofctl -F OXM-OpenFlow15 -O OpenFlow15 -vwarn dump-groups br0 1234], [0], [stdout])
AT_CHECK([strip_xids < stdout], [0], [dnl
OFPST_GROUP_DESC reply (OF1.5):
 group_id=1234,type=all,bucket=bucket_id:10,actions=output:10,bucket=bucket_id:11,actions=output:11
])

# Start over again, then add two buckets using "first".
AT_DATA([groups.txt], [dnl
delete group_id=1234
add group_id=1234,type=all
insert_bucket group_id=1234,command_bucket_id=first,bucket=bucket_id:10,actions=output:10,bucket=bucket_id:11,actions=output:11
])
AT_CHECK([ovs-ofctl --bundle -O OpenFlow15 -vwarn add-groups br0 groups.txt])
AT_CHECK([ovs-ofctl -F OXM-OpenFlow15 -O OpenFlow15 -vwarn dump-groups br0 1234], [0], [stdout])
AT_CHECK([strip_xids < stdout], [0], [dnl
OFPST_GROUP_DESC reply (OF1.5):
 group_id=1234,type=all,bucket=bucket_id:10,actions=output:10,bucket=bucket_id:11,actions=output:11
])

# Add two more buckets before the existing ones.
AT_CHECK([ovs-ofctl --bundle -O OpenFlow15 -vwarn insert-buckets br0 group_id=1234,command_bucket_id=first,bucket=bucket_id:0,actions=output:0,bucket=bucket_id:1,actions=output:1])
AT_CHECK([ovs-ofctl -O OpenFlow15 -vwarn dump-groups br0], [0], [stdout])
AT_CHECK([strip_xids < stdout], [0], [dnl
OFPST_GROUP_DESC reply (OF1.5):
 group_id=1234,type=all,bucket=bucket_id:0,actions=output:0,bucket=bucket_id:1,actions=output:1,bucket=bucket_id:10,actions=output:10,bucket=bucket_id:11,actions=output:11
])

# Add another bucket at the end.
AT_CHECK([ovs-ofctl --bundle -O OpenFlow15 -vwarn insert-buckets br0 group_id=1234,command_bucket_id=last,bucket=bucket_id:14,actions=output:14,bucket=bucket_id:15,actions=output:15])
AT_CHECK([ovs-ofctl -O OpenFlow15 -vwarn dump-groups br0], [0], [stdout])
AT_CHECK([strip_xids < stdout], [0], [dnl
OFPST_GROUP_DESC reply (OF1.5):
 group_id=1234,type=all,bucket=bucket_id:0,actions=output:0,bucket=bucket_id:1,actions=output:1,bucket=bucket_id:10,actions=output:10,bucket=bucket_id:11,actions=output:11,bucket=bucket_id:14,actions=output:14,bucket=bucket_id:15,actions=output:15
])

# Verify that duplicate bucket IDs are rejected.
AT_CHECK([ovs-ofctl --bundle -O OpenFlow15 -vwarn insert-buckets br0 group_id=1234,command_bucket_id=last,bucket=bucket_id:14,actions=output:14,bucket=bucket_id:15,actions=output:15], [1], [], [stderr])
AT_CHECK([strip_xids < stderr | sed '/talking to/,$d'], [0], [dnl
Error OFPGMFC_BUCKET_EXISTS for: OFPT_GROUP_MOD (OF1.5):
 INSERT_BUCKET command_bucket_id:last,group_id=1234,bucket=bucket_id:14,actions=output:14,bucket=bucket_id:15,actions=output:15
Error OFPBFC_MSG_FAILED for: OFPT_BUNDLE_CONTROL (OF1.5):
 bundle_id=0 type=COMMIT_REQUEST flags=atomic ordered
])

# Add another bucket just before bucket 15.
AT_CHECK([ovs-ofctl --bundle -O OpenFlow15 -vwarn insert-buckets br0 group_id=1234,command_bucket_id=15])
AT_CHECK([ovs-ofctl -O OpenFlow15 -vwarn dump-groups br0], [0], [stdout])
AT_CHECK([strip_xids < stdout], [0], [dnl
OFPST_GROUP_DESC reply (OF1.5):
 group_id=1234,type=all,bucket=bucket_id:0,actions=output:0,bucket=bucket_id:1,actions=output:1,bucket=bucket_id:10,actions=output:10,bucket=bucket_id:11,actions=output:11,bucket=bucket_id:14,actions=output:14,bucket=bucket_id:15,actions=output:15
])

# Add two more buckets just before bucket 11,
# getting the command from a file.
AT_DATA([buckets.txt], [dnl
group_id=1234,command_bucket_id=11,bucket=bucket_id:12,actions=output:12,bucket=bucket_id:13,actions=output:13
])
AT_CHECK([ovs-ofctl --bundle -O OpenFlow15 -vwarn insert-buckets br0 - < buckets.txt])
AT_CHECK([ovs-ofctl -O OpenFlow15 -vwarn dump-groups br0], [0], [stdout])
AT_CHECK([strip_xids < stdout], [0], [dnl
OFPST_GROUP_DESC reply (OF1.5):
 group_id=1234,type=all,bucket=bucket_id:0,actions=output:0,bucket=bucket_id:1,actions=output:1,bucket=bucket_id:10,actions=output:10,bucket=bucket_id:11,actions=output:11,bucket=bucket_id:12,actions=output:12,bucket=bucket_id:13,actions=output:13,bucket=bucket_id:14,actions=output:14,bucket=bucket_id:15,actions=output:15
])

# Add yet two more buckets.
AT_CHECK([ovs-ofctl --bundle -O OpenFlow15 -vwarn insert-buckets br0 group_id=1234,command_bucket_id=15,bucket=bucket_id:20,actions=output:20,bucket=bucket_id:21,actions=output:21])
AT_CHECK([ovs-ofctl -O OpenFlow15 -vwarn dump-groups br0], [0], [stdout])
AT_CHECK([strip_xids < stdout], [0], [dnl
OFPST_GROUP_DESC reply (OF1.5):
 group_id=1234,type=all,bucket=bucket_id:0,actions=output:0,bucket=bucket_id:1,actions=output:1,bucket=bucket_id:10,actions=output:10,bucket=bucket_id:11,actions=output:11,bucket=bucket_id:12,actions=output:12,bucket=bucket_id:13,actions=output:13,bucket=bucket_id:14,actions=output:14,bucket=bucket_id:15,actions=output:15,bucket=bucket_id:20,actions=output:20,bucket=bucket_id:21,actions=output:21
])

# Negative tests.
AT_CHECK([ovs-ofctl --bundle -O OpenFlow15 -vwarn insert-buckets br0 group_id=1234,command_bucket_id=0xffffff01,bucket=bucket_id:0,actions=output:0,bucket=bucket_id:1,actions=output:1], [1], [],
  [ovs-ofctl: invalid command bucket id 4294967041
])
AT_CHECK([ovs-ofctl --bundle -vwarn insert-buckets br0 group_id=1234,command_bucket_id=first,bucket=bucket_id:0,actions=output:0,bucket=bucket_id:1,actions=output:1], [1], [],
  [ovs-ofctl: insert-bucket needs OpenFlow 1.5 or later ('-O OpenFlow15')
])
OVS_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([ofproto - bundle remove group buckets])
OVS_VSWITCHD_START
AT_DATA([groups.txt], [dnl
group_id=1234,type=all,bucket=bucket_id:10,actions=output:10,bucket=bucket_id:11,actions=output:11,bucket=bucket_id:12,actions=output:12,bucket=bucket_id:13,actions=output:13,bucket=bucket_id:14,actions=output:14,bucket=bucket_id:15,actions=output:15,bucket=bucket_id:16,actions=output:16
])
AT_CHECK([ovs-ofctl --bundle -O OpenFlow15 -vwarn add-groups br0 groups.txt])
AT_CHECK([ovs-ofctl -F OXM-OpenFlow15 -O OpenFlow15 -vwarn dump-groups br0 1234], [0], [stdout])
AT_CHECK([strip_xids < stdout], [0], [dnl
OFPST_GROUP_DESC reply (OF1.5):
 group_id=1234,type=all,bucket=bucket_id:10,actions=output:10,bucket=bucket_id:11,actions=output:11,bucket=bucket_id:12,actions=output:12,bucket=bucket_id:13,actions=output:13,bucket=bucket_id:14,actions=output:14,bucket=bucket_id:15,actions=output:15,bucket=bucket_id:16,actions=output:16
])
AT_CHECK([ovs-ofctl --bundle -O OpenFlow15 -vwarn remove-buckets br0 group_id=1234,command_bucket_id=first])
AT_CHECK([ovs-ofctl -O OpenFlow15 -vwarn dump-groups br0], [0], [stdout])
AT_CHECK([strip_xids < stdout], [0], [dnl
OFPST_GROUP_DESC reply (OF1.5):
 group_id=1234,type=all,bucket=bucket_id:11,actions=output:11,bucket=bucket_id:12,actions=output:12,bucket=bucket_id:13,actions=output:13,bucket=bucket_id:14,actions=output:14,bucket=bucket_id:15,actions=output:15,bucket=bucket_id:16,actions=output:16
])
AT_CHECK([ovs-ofctl --bundle -O OpenFlow15 -vwarn remove-buckets br0 group_id=1234,command_bucket_id=last])
AT_CHECK([ovs-ofctl -O OpenFlow15 -vwarn dump-groups br0], [0], [stdout])
AT_CHECK([strip_xids < stdout], [0], [dnl
OFPST_GROUP_DESC reply (OF1.5):
 group_id=1234,type=all,bucket=bucket_id:11,actions=output:11,bucket=bucket_id:12,actions=output:12,bucket=bucket_id:13,actions=output:13,bucket=bucket_id:14,actions=output:14,bucket=bucket_id:15,actions=output:15
])
AT_CHECK([ovs-ofctl --bundle -O OpenFlow15 -vwarn remove-buckets br0 group_id=1234,command_bucket_id=13])
AT_CHECK([ovs-ofctl -O OpenFlow15 -vwarn dump-groups br0], [0], [stdout])
AT_CHECK([strip_xids < stdout], [0], [dnl
OFPST_GROUP_DESC reply (OF1.5):
 group_id=1234,type=all,bucket=bucket_id:11,actions=output:11,bucket=bucket_id:12,actions=output:12,bucket=bucket_id:14,actions=output:14,bucket=bucket_id:15,actions=output:15
])
AT_DATA([buckets.txt], [dnl
group_id=1234
])
AT_CHECK([ovs-ofctl --bundle -O OpenFlow15 -vwarn remove-buckets br0 - < buckets.txt])
AT_CHECK([ovs-ofctl -O OpenFlow15 -vwarn dump-groups br0], [0], [stdout])
AT_CHECK([strip_xids < stdout], [0], [dnl
OFPST_GROUP_DESC reply (OF1.5):
 group_id=1234,type=all
])
AT_CHECK([ovs-ofctl --bundle -O OpenFlow15 -vwarn remove-buckets br0 group_id=1234,command_bucket_id=first])
AT_CHECK([ovs-ofctl --bundle -O OpenFlow15 -vwarn remove-buckets br0 group_id=1234,command_bucket_id=last])
AT_CHECK([ovs-ofctl --bundle -O OpenFlow15 -vwarn remove-buckets br0 group_id=1234,command_bucket_id=all])
AT_CHECK([ovs-ofctl --bundle -O OpenFlow15 -vwarn remove-buckets br0 group_id=1234,command_bucket_id=1], [1], [], [stderr])
AT_CHECK([ofctl_strip < stderr | sed '/talking to/,$d'], [0], [dnl
Error OFPGMFC_UNKNOWN_BUCKET for: OFPT_GROUP_MOD (OF1.5):
 REMOVE_BUCKET command_bucket_id:1,group_id=1234
Error OFPBFC_MSG_FAILED for: OFPT_BUNDLE_CONTROL (OF1.5):
 bundle_id=0 type=COMMIT_REQUEST flags=atomic ordered
])
# Negative test.
AT_CHECK([ovs-ofctl --bundle -O OpenFlow11 -vwarn remove-buckets br0 group_id=1234,command_bucket_id=last], [1], [],
  [ovs-ofctl: none of the usable flow formats (OXM-OpenFlow15) is among the allowed flow formats (OXM-OpenFlow14)
])
OVS_VSWITCHD_STOP
AT_CLEANUP

dnl This is really bare-bones.
dnl It at least checks request and reply serialization and deserialization.
AT_SETUP([ofproto - flow mod checks group availability])
OVS_VSWITCHD_START
AT_CHECK([ovs-ofctl -O OpenFlow11 -vwarn add-group br0 group_id=1234,type=all,bucket=output:10])
AT_DATA([flows.txt], [dnl
tcp actions=group:1234
udp actions=group:1235
])
AT_CHECK([ovs-ofctl -O OpenFlow11 -vwarn add-flow br0 'tcp actions=group:1234'])
AT_CHECK([ovs-ofctl -O OpenFlow11 -vwarn add-flow br0 'tcp actions=group:1235'], [1], [], [stderr])

AT_CHECK([strip_xids < stderr], [0],
  [OFPT_ERROR (OF1.1): OFPBAC_BAD_OUT_GROUP
OFPT_FLOW_MOD (OF1.1): ADD tcp actions=group:1235
])
OVS_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([ofproto - bundle flow mod checks group availability])
OVS_VSWITCHD_START
AT_DATA([bundle.txt], [dnl
group add group_id=1234,type=all,bucket=output:10
flow add tcp actions=group:1234
flow add udp actions=group:1235
])
AT_CHECK([ovs-ofctl -vwarn bundle br0 bundle.txt], [1], [], [stderr])

AT_CHECK([ofctl_strip < stderr | sed '/talking to/,$d'], [0],
  [dnl
Error OFPBAC_BAD_OUT_GROUP for: OFPT_FLOW_MOD (OF1.4): ADD udp actions=group:1235
Error OFPBFC_MSG_FAILED for: OFPT_BUNDLE_CONTROL (OF1.4):
 bundle_id=0 type=COMMIT_REQUEST flags=atomic ordered
])
OVS_VSWITCHD_STOP
AT_CLEANUP

dnl This is really bare-bones.
dnl It at least checks request and reply serialization and deserialization.
AT_SETUP([ofproto - group description])
OVS_VSWITCHD_START
AT_CHECK([ovs-ofctl -O OpenFlow11 -vwarn add-group br0 group_id=1234,type=all,bucket=output:10], [0], [stdout])
AT_CHECK([ovs-ofctl -O OpenFlow11 -vwarn dump-groups br0], [0], [stdout])
AT_CHECK([strip_xids < stdout], [0], [dnl
OFPST_GROUP_DESC reply (OF1.1):
 group_id=1234,type=all,bucket=actions=output:10
])
OVS_VSWITCHD_STOP
AT_CLEANUP

dnl This is really bare-bones.
dnl It at least checks request and reply serialization and deserialization.
AT_SETUP([ofproto - group features (OpenFlow 1.0 extension)])
OVS_VSWITCHD_START
AT_CHECK([ovs-ofctl -O OpenFlow10 -vwarn dump-group-features br0], [0], [stdout])
AT_CHECK([strip_xids < stdout], [0], [dnl
NXST_GROUP_FEATURES reply:
 Group table:
    Types:  0xf
    Capabilities:  0x7
    all group:
       max_groups=0xffffff00
       actions: output enqueue set_vlan_vid set_vlan_pcp strip_vlan mod_dl_src mod_dl_dst mod_nw_src mod_nw_dst mod_nw_tos mod_tp_src mod_tp_dst
    select group:
       max_groups=0xffffff00
       actions: output enqueue set_vlan_vid set_vlan_pcp strip_vlan mod_dl_src mod_dl_dst mod_nw_src mod_nw_dst mod_nw_tos mod_tp_src mod_tp_dst
    indirect group:
       max_groups=0xffffff00
       actions: output enqueue set_vlan_vid set_vlan_pcp strip_vlan mod_dl_src mod_dl_dst mod_nw_src mod_nw_dst mod_nw_tos mod_tp_src mod_tp_dst
    fast failover group:
       max_groups=0xffffff00
       actions: output enqueue set_vlan_vid set_vlan_pcp strip_vlan mod_dl_src mod_dl_dst mod_nw_src mod_nw_dst mod_nw_tos mod_tp_src mod_tp_dst
])
OVS_VSWITCHD_STOP
AT_CLEANUP

dnl This is really bare-bones.
dnl It at least checks request and reply serialization and deserialization.
AT_SETUP([ofproto - group features (OpenFlow 1.2)])
OVS_VSWITCHD_START
AT_CHECK([ovs-ofctl -O OpenFlow12 -vwarn dump-group-features br0], [0], [stdout])
AT_CHECK([strip_xids < stdout], [0], [dnl
OFPST_GROUP_FEATURES reply (OF1.2):
 Group table:
    Types:  0xf
    Capabilities:  0x7
    all group:
       max_groups=0xffffff00
       actions: output group set_field strip_vlan push_vlan mod_nw_ttl dec_ttl set_mpls_ttl dec_mpls_ttl push_mpls pop_mpls set_queue
    select group:
       max_groups=0xffffff00
       actions: output group set_field strip_vlan push_vlan mod_nw_ttl dec_ttl set_mpls_ttl dec_mpls_ttl push_mpls pop_mpls set_queue
    indirect group:
       max_groups=0xffffff00
       actions: output group set_field strip_vlan push_vlan mod_nw_ttl dec_ttl set_mpls_ttl dec_mpls_ttl push_mpls pop_mpls set_queue
    fast failover group:
       max_groups=0xffffff00
       actions: output group set_field strip_vlan push_vlan mod_nw_ttl dec_ttl set_mpls_ttl dec_mpls_ttl push_mpls pop_mpls set_queue
])
OVS_VSWITCHD_STOP
AT_CLEANUP

dnl This is really bare-bones.
dnl It at least checks request and reply serialization and deserialization.
AT_SETUP([ofproto - group stats (OpenFlow 1.0 extension)])
OVS_VSWITCHD_START
AT_DATA([groups.txt], [dnl
group_id=1234,type=all,bucket=output:10
group_id=1235,type=all,bucket=output:10
])
AT_CHECK([ovs-ofctl -O OpenFlow10 -vwarn add-groups br0 groups.txt])
AT_CHECK([ovs-ofctl -O OpenFlow10 -vwarn add-flow br0 'tcp actions=group:1234'])
AT_CHECK([ovs-ofctl -O OpenFlow10 -vwarn dump-group-stats br0 group_id=1234], [0], [stdout])
AT_CHECK([strip_xids < stdout | sed 's/duration=[[0-9.]]*s/duration=?s/' | sort], [0], [dnl
 group_id=1234,duration=?s,ref_count=1,packet_count=0,byte_count=0,bucket0:packet_count=0,byte_count=0
NXST_GROUP reply:
])
AT_CHECK([ovs-ofctl -O OpenFlow10 -vwarn dump-group-stats br0], [0], [stdout])
AT_CHECK([strip_xids < stdout | sed 's/duration=[[0-9.]]*s/duration=?s/' | sort], [0], [dnl
 group_id=1234,duration=?s,ref_count=1,packet_count=0,byte_count=0,bucket0:packet_count=0,byte_count=0
 group_id=1235,duration=?s,ref_count=0,packet_count=0,byte_count=0,bucket0:packet_count=0,byte_count=0
NXST_GROUP reply:
])
OVS_VSWITCHD_STOP
AT_CLEANUP

dnl This is really bare-bones.
dnl It at least checks request and reply serialization and deserialization.
AT_SETUP([ofproto - group stats (OpenFlow 1.1)])
OVS_VSWITCHD_START
AT_DATA([groups.txt], [dnl
group_id=1234,type=all,bucket=output:10
group_id=1235,type=all,bucket=output:10
])
AT_CHECK([ovs-ofctl -O OpenFlow11 -vwarn add-groups br0 groups.txt])
AT_CHECK([ovs-ofctl -O OpenFlow11 -vwarn add-flow br0 'tcp actions=group:1234'])
AT_CHECK([ovs-ofctl -O OpenFlow11 -vwarn dump-group-stats br0 group_id=1234], [0], [stdout])
AT_CHECK([strip_xids < stdout | sort], [0], [dnl
 group_id=1234,ref_count=1,packet_count=0,byte_count=0,bucket0:packet_count=0,byte_count=0
OFPST_GROUP reply (OF1.1):
])
AT_CHECK([ovs-ofctl -O OpenFlow11 -vwarn dump-group-stats br0], [0], [stdout])
AT_CHECK([strip_xids < stdout | sort], [0], [dnl
 group_id=1234,ref_count=1,packet_count=0,byte_count=0,bucket0:packet_count=0,byte_count=0
 group_id=1235,ref_count=0,packet_count=0,byte_count=0,bucket0:packet_count=0,byte_count=0
OFPST_GROUP reply (OF1.1):
])
OVS_VSWITCHD_STOP
AT_CLEANUP

dnl This is really bare-bones.
dnl It at least checks request and reply serialization and deserialization.
AT_SETUP([ofproto - group stats (OpenFlow 1.3)])
OVS_VSWITCHD_START
AT_DATA([groups.txt], [dnl
group_id=1234,type=all,bucket=output:10
group_id=1235,type=all,bucket=output:10
])
AT_CHECK([ovs-ofctl -O OpenFlow13 -vwarn add-groups br0 groups.txt])
AT_CHECK([ovs-ofctl -O OpenFlow13 -vwarn add-flow br0 'tcp actions=group:1234'])
AT_CHECK([ovs-ofctl -O OpenFlow13 -vwarn dump-group-stats br0 group_id=1234], [0], [stdout])
AT_CHECK([strip_xids < stdout | sed 's/duration=[[0-9.]]*s/duration=?s/' | sort], [0], [dnl
 group_id=1234,duration=?s,ref_count=1,packet_count=0,byte_count=0,bucket0:packet_count=0,byte_count=0
OFPST_GROUP reply (OF1.3):
])
AT_CHECK([ovs-ofctl -O OpenFlow13 -vwarn dump-group-stats br0], [0], [stdout])
AT_CHECK([strip_xids < stdout | sed 's/duration=[[0-9.]]*s/duration=?s/' | sort], [0], [dnl
 group_id=1234,duration=?s,ref_count=1,packet_count=0,byte_count=0,bucket0:packet_count=0,byte_count=0
 group_id=1235,duration=?s,ref_count=0,packet_count=0,byte_count=0,bucket0:packet_count=0,byte_count=0
OFPST_GROUP reply (OF1.3):
])
OVS_VSWITCHD_STOP
AT_CLEANUP

dnl This is really bare-bones.
dnl It at least checks request and reply serialization and deserialization.
AT_SETUP([ofproto - group stats (OpenFlow 1.5)])
OVS_VSWITCHD_START
AT_DATA([groups.txt], [dnl
group_id=1234,type=all,bucket=output:10
group_id=1235,type=all,bucket=output:10
])
AT_CHECK([ovs-ofctl -O OpenFlow15 -vwarn add-groups br0 groups.txt])
AT_CHECK([ovs-ofctl -O OpenFlow15 -vwarn add-flow br0 'tcp actions=group:1234'])
AT_CHECK([ovs-ofctl -O OpenFlow15 -vwarn dump-group-stats br0 group_id=1234], [0], [stdout])
AT_CHECK([strip_xids < stdout | sed 's/duration=[[0-9.]]*s/duration=?s/' | sort], [0], [dnl
 group_id=1234,duration=?s,ref_count=1,packet_count=0,byte_count=0,bucket0:packet_count=0,byte_count=0
OFPST_GROUP reply (OF1.5):
])
AT_CHECK([ovs-ofctl -O OpenFlow15 -vwarn dump-group-stats br0], [0], [stdout])
AT_CHECK([strip_xids < stdout | sed 's/duration=[[0-9.]]*s/duration=?s/' | sort], [0], [dnl
 group_id=1234,duration=?s,ref_count=1,packet_count=0,byte_count=0,bucket0:packet_count=0,byte_count=0
 group_id=1235,duration=?s,ref_count=0,packet_count=0,byte_count=0,bucket0:packet_count=0,byte_count=0
OFPST_GROUP reply (OF1.5):
])
OVS_VSWITCHD_STOP
AT_CLEANUP

dnl This is used to find that the bucket counter is not updated.
AT_SETUP([ofproto - group stats after insert a new bucket (OpenFlow 1.5)])
OVS_VSWITCHD_START
AT_DATA([groups.txt], [dnl
group_id=1234,type=select,selection_method=hash bucket=bucket_id=1,weight:100,actions=output:10
])
AT_CHECK([ovs-ofctl -O OpenFlow15 -vwarn add-groups br0 groups.txt])
AT_CHECK([ovs-ofctl -O OpenFlow15 -vwarn insert-buckets br0 'group_id=1234, command_bucket_id=last, bucket=bucket_id=2,weight:100,actions=output:10'])
AT_CHECK([ovs-ofctl -O OpenFlow15 -vwarn dump-group-stats br0 group_id=1234], [0], [stdout])
AT_CHECK([strip_xids < stdout | sed 's/duration=[[0-9.]]*s/duration=?s/' | sort], [0], [dnl
 group_id=1234,duration=?s,ref_count=0,packet_count=0,byte_count=0,bucket0:packet_count=0,byte_count=0,bucket1:packet_count=0,byte_count=0
OFPST_GROUP reply (OF1.5):
])
OVS_VSWITCHD_STOP
AT_CLEANUP

dnl This found a use-after-free error in bridge destruction in the
dnl presence of groups.
AT_SETUP([ofproto - group add then bridge delete (OpenFlow 1.3)])
OVS_VSWITCHD_START
AT_DATA([groups.txt], [dnl
group_id=1234,type=all,bucket=output:10
group_id=1235,type=all,bucket=output:10

dnl This checks for regression against a parser bug such that
dnl "actions=resbmit(,1)" etc. was rejected as a syntax error.
group_id=2345,type=select,bucket=weight:10,actions=resubmit(,1),bucket=weight:10,actions=resubmit(,2),bucket=weight:1,actions=resubmit(,3)
])
AT_CHECK([ovs-ofctl -O OpenFlow13 -vwarn add-groups br0 groups.txt])
AT_CHECK([ovs-vsctl del-br br0])
OVS_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([ofproto - mod-port (OpenFlow 1.0)])
OVS_VSWITCHD_START
for command_config_state in \
    'up 0 0' \
    'noflood NO_FLOOD 0' \
    'flood 0 0' \
    'no-receive NO_RECV 0' \
    'no-forward NO_RECV,NO_FWD 0' \
    'no-packet-in NO_RECV,NO_FWD,NO_PACKET_IN 0' \
    'forward NO_RECV,NO_PACKET_IN 0' \
    'packet-in NO_RECV 0' \
    'up NO_RECV 0' \
    'receive 0 0' \
    'down PORT_DOWN LINK_DOWN'
do
    printf '\n--- %s --- \n\n' "$command_config_state"
    set $command_config_state
    command=$[1] config=`echo $[2] | sed 's/,/ /g'` state=$[3]
    AT_CHECK([ovs-ofctl -vwarn mod-port br0 br0 $command])
    AT_CHECK([ovs-ofctl -vwarn show br0], [0], [stdout])
    AT_CHECK_UNQUOTED([strip_xids < stdout], [0], [dnl
OFPT_FEATURES_REPLY: dpid:fedcba9876543210
n_tables:254, n_buffers:0
capabilities: FLOW_STATS TABLE_STATS PORT_STATS QUEUE_STATS ARP_MATCH_IP
actions: output enqueue set_vlan_vid set_vlan_pcp strip_vlan mod_dl_src mod_dl_dst mod_nw_src mod_nw_dst mod_nw_tos mod_tp_src mod_tp_dst
 LOCAL(br0): addr:aa:55:aa:55:00:00
     config:     $config
     state:      $state
     speed: 0 Mbps now, 0 Mbps max
OFPT_GET_CONFIG_REPLY: frags=normal miss_send_len=0
])
done
OVS_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([ofproto - mod-port (OpenFlow 1.2)])
OVS_VSWITCHD_START
for command_config_state in \
    'up 0 LIVE' \
    'no-receive NO_RECV LIVE' \
    'no-forward NO_RECV,NO_FWD LIVE' \
    'no-packet-in NO_RECV,NO_FWD,NO_PACKET_IN LIVE' \
    'forward NO_RECV,NO_PACKET_IN LIVE' \
    'packet-in NO_RECV LIVE' \
    'up NO_RECV LIVE' \
    'receive 0 LIVE' \
    'down PORT_DOWN LINK_DOWN'
do
    printf '\n--- %s --- \n\n' "$command_config_state"
    set $command_config_state
    command=$[1] config=`echo $[2] | sed 's/,/ /g'` state=$[3]
    AT_CHECK([ovs-ofctl -O OpenFlow12 -vwarn mod-port br0 br0 $command])
    AT_CHECK([ovs-ofctl -O OpenFlow12 -vwarn show br0], [0], [stdout])
    AT_CHECK_UNQUOTED([strip_xids < stdout], [0], [dnl
OFPT_FEATURES_REPLY (OF1.2): dpid:fedcba9876543210
n_tables:254, n_buffers:0
capabilities: FLOW_STATS TABLE_STATS PORT_STATS GROUP_STATS QUEUE_STATS
 LOCAL(br0): addr:aa:55:aa:55:00:00
     config:     $config
     state:      $state
     speed: 0 Mbps now, 0 Mbps max
OFPT_GET_CONFIG_REPLY (OF1.2): frags=normal miss_send_len=0
])
done
OVS_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([ofproto - mod-port (OpenFlow 1.4)])
OVS_VSWITCHD_START
for command_config_state in \
    'up 0 LIVE' \
    'no-receive NO_RECV LIVE' \
    'no-forward NO_RECV,NO_FWD LIVE' \
    'no-packet-in NO_RECV,NO_FWD,NO_PACKET_IN LIVE' \
    'forward NO_RECV,NO_PACKET_IN LIVE' \
    'packet-in NO_RECV LIVE' \
    'up NO_RECV LIVE' \
    'receive 0 LIVE' \
    'down PORT_DOWN LINK_DOWN'
do
    printf '\n--- %s --- \n\n' "$command_config_state"
    set $command_config_state
    command=$[1] config=`echo $[2] | sed 's/,/ /g'` state=$[3]
    AT_CHECK([ovs-ofctl -O OpenFlow14 -vwarn mod-port br0 br0 $command])
    AT_CHECK([ovs-ofctl -O OpenFlow14 -vwarn show br0], [0], [stdout])
    AT_CHECK_UNQUOTED([strip_xids < stdout], [0], [dnl
OFPT_FEATURES_REPLY (OF1.4): dpid:fedcba9876543210
n_tables:254, n_buffers:0
capabilities: FLOW_STATS TABLE_STATS PORT_STATS GROUP_STATS QUEUE_STATS BUNDLES
OFPST_PORT_DESC reply (OF1.4):
 LOCAL(br0): addr:aa:55:aa:55:00:00
     config:     $config
     state:      $state
     speed: 0 Mbps now, 0 Mbps max
OFPT_GET_CONFIG_REPLY (OF1.4): frags=normal miss_send_len=0
])
done
OVS_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([ofproto - basic flow_mod commands (NXM)])
OVS_VSWITCHD_START
AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip], [0], [NXST_FLOW reply:
])
AT_CHECK([echo 'in_port=2,actions=1' | ovs-ofctl add-flows br0 -])
AT_CHECK([ovs-ofctl add-flow br0 in_port=1,actions=2])
AT_CHECK([ovs-ofctl -F nxm add-flow br0 table=1,in_port=4,actions=3])
AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort], [0], [dnl
 in_port=1 actions=output:2
 in_port=2 actions=output:1
 table=1, in_port=4 actions=output:3
NXST_FLOW reply:
])
AT_CHECK([ovs-ofctl dump-aggregate br0 table=0 | strip_xids], [0], [dnl
NXST_AGGREGATE reply: packet_count=0 byte_count=0 flow_count=2
])
AT_CHECK([ovs-ofctl del-flows br0])
AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip], [0], [NXST_FLOW reply:
])
OVS_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([ofproto - basic flow_mod commands (OpenFlow 1.0)])
OVS_VSWITCHD_START
AT_CHECK([ovs-ofctl -F openflow10 dump-flows br0 | ofctl_strip], [0], [OFPST_FLOW reply:
])
AT_CHECK([echo 'in_port=2,actions=1' | ovs-ofctl -F openflow10 add-flows br0 -])
AT_CHECK([ovs-ofctl -F openflow10 add-flow br0 in_port=1,actions=2])
AT_CHECK([ovs-ofctl -F openflow10 add-flow br0 table=1,in_port=4,actions=3])
AT_CHECK([ovs-ofctl -F openflow10 dump-flows br0 | ofctl_strip | sort], [0], [dnl
 in_port=1 actions=output:2
 in_port=2 actions=output:1
 table=1, in_port=4 actions=output:3
OFPST_FLOW reply:
])
AT_CHECK([ovs-ofctl -F openflow10 dump-aggregate br0 table=0 | strip_xids], [0], [dnl
OFPST_AGGREGATE reply: packet_count=0 byte_count=0 flow_count=2
])
AT_CHECK([ovs-ofctl -F openflow10 del-flows br0])
AT_CHECK([ovs-ofctl -F openflow10 dump-flows br0 | ofctl_strip], [0], [OFPST_FLOW reply:
])
OVS_VSWITCHD_STOP
AT_CLEANUP

# It's really dumb that check_overlap and reset_counts are considered
# part of flow state, but OpenFlow implies that it is, and OFTest and
# some users insist on it.
AT_SETUP([ofproto - add-flow and flags])
OVS_VSWITCHD_START
AT_CHECK([ovs-ofctl -F openflow10 add-flow br0 check_overlap,in_port=1,actions=drop])
# Prior to OF1.3, flow dumps didn't include a "flags" field.
AT_CHECK([ovs-ofctl -F openflow10 dump-flows br0 | ofctl_strip], [0], [dnl
OFPST_FLOW reply:
 in_port=1 actions=drop
])
AT_CHECK([ovs-ofctl -O OpenFlow11 dump-flows br0 | ofctl_strip], [0], [dnl
OFPST_FLOW reply (OF1.1):
 in_port=1 actions=drop
])
AT_CHECK([ovs-ofctl -O OpenFlow12 dump-flows br0 | ofctl_strip], [0], [dnl
OFPST_FLOW reply (OF1.2):
 in_port=1 actions=drop
])
# OF1.3 makes the flags visible.
AT_CHECK([ovs-ofctl -O OpenFlow13 dump-flows br0 | ofctl_strip], [0], [dnl
OFPST_FLOW reply (OF1.3):
 check_overlap reset_counts in_port=1 actions=drop
])
AT_CHECK([ovs-ofctl -O OpenFlow14 dump-flows br0 | ofctl_strip], [0], [dnl
OFPST_FLOW reply (OF1.4):
 check_overlap reset_counts in_port=1 actions=drop
])
# OF1.5 makes the flags invisible.
AT_CHECK([ovs-ofctl -O OpenFlow15 dump-flows br0 | ofctl_strip], [0], [dnl
OFPST_FLOW reply (OF1.5):
 check_overlap reset_counts in_port=1 actions=drop
])
OVS_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([ofproto - basic flow_mod commands (OpenFlow 1.1)])
OVS_VSWITCHD_START
AT_CHECK([ovs-ofctl -O OpenFlow11 dump-flows br0 | ofctl_strip], [0], [OFPST_FLOW reply (OF1.1):
])
AT_CHECK([echo 'in_port=2,actions=1' | ovs-ofctl -O OpenFlow11 add-flows br0 -])
AT_CHECK([ovs-ofctl -O OpenFlow11 add-flow br0 in_port=1,actions=2])
AT_CHECK([ovs-ofctl -O OpenFlow11 add-flow br0 table=1,in_port=4,actions=3])
AT_CHECK([ovs-ofctl -O OpenFlow11 dump-flows br0 | ofctl_strip | sort], [0], [dnl
 in_port=1 actions=output:2
 in_port=2 actions=output:1
 table=1, in_port=4 actions=output:3
OFPST_FLOW reply (OF1.1):
])
AT_CHECK([ovs-ofctl -O OpenFlow11 dump-aggregate br0 table=0 | strip_xids], [0], [dnl
OFPST_AGGREGATE reply (OF1.1): packet_count=0 byte_count=0 flow_count=2
])
AT_CHECK([ovs-ofctl -O OpenFlow11 del-flows br0])
AT_CHECK([ovs-ofctl -O OpenFlow11 dump-flows br0 | ofctl_strip], [0], [OFPST_FLOW reply (OF1.1):
 table=1, in_port=4 actions=output:3
])
OVS_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([ofproto - flow_mod negative test (OpenFlow 1.1)])
OVS_VSWITCHD_START(
  [set bridge br0 protocols=OpenFlow10,OpenFlow11,OpenFlow12,OpenFlow13])
AT_CHECK([ovs-ofctl add-flow -O OpenFlow11 br0 table=1,action=goto_table:2])

# The error message here actually comes from ovs-ofctl, not from ovs-vswitchd,
# but at least it's the same code in ofpacts_check() that issues the error.
AT_CHECK([ovs-ofctl add-flow -O OpenFlow11 br0 table=1,action=goto_table:1],
  [1], [],
  [ovs-ofctl: actions are invalid with specified match (OFPBIC_BAD_TABLE_ID)
])
OVS_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([ofproto - set-field flow_mod commands (NXM)])
OVS_VSWITCHD_START
AT_CHECK([ovs-ofctl add-flow br0 ipv6,table=1,in_port=3,actions=drop])
AT_CHECK([ovs-ofctl add-flow br0 ipv6,table=1,in_port=3,actions=set_field:fe80:0123:4567:890a:a6ba:dbff:fefe:59fa-\>ipv6_src])
AT_CHECK([ovs-ofctl add-flow br0 icmp6,icmp_type=136,table=1,in_port=3,actions=set_field:fe80:8675:3097:890a:a6ba:dbff:f00d:59fa-\>nd_target,set_field:cc:dd:ee:ff:00:11-\>nd_tll])
AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort], [0], [dnl
 table=1, icmp6,in_port=3,icmp_type=136 actions=load:0xa6badbfff00d59fa->NXM_NX_ND_TARGET[[0..63]],load:0xfe8086753097890a->NXM_NX_ND_TARGET[[64..127]],load:0xccddeeff0011->NXM_NX_ND_TLL[[]]
 table=1, ipv6,in_port=3 actions=load:0xa6badbfffefe59fa->NXM_NX_IPV6_SRC[[0..63]],load:0xfe8001234567890a->NXM_NX_IPV6_SRC[[64..127]]
NXST_FLOW reply:
])
OVS_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([ofproto - basic flow_mod commands (OpenFlow 1.2)])
OVS_VSWITCHD_START
AT_CHECK([ovs-ofctl -O OpenFlow12 dump-flows br0 | ofctl_strip], [0], [OFPST_FLOW reply (OF1.2):
])
AT_CHECK([echo 'in_port=2,actions=1' | ovs-ofctl -O OpenFlow12 add-flows br0 -])
AT_CHECK([ovs-ofctl -O OpenFlow12 add-flow br0 in_port=1,actions=2])
AT_CHECK([ovs-ofctl -O OpenFlow12 add-flow br0 table=1,in_port=4,actions=3])
AT_CHECK([ovs-ofctl -O OpenFlow12 dump-flows br0 | ofctl_strip | sort], [0], [dnl
 in_port=1 actions=output:2
 in_port=2 actions=output:1
 table=1, in_port=4 actions=output:3
OFPST_FLOW reply (OF1.2):
])
AT_CHECK([ovs-ofctl -O OpenFlow12 del-flows br0])
AT_CHECK([ovs-ofctl -O OpenFlow12 dump-flows br0 | ofctl_strip], [0], [OFPST_FLOW reply (OF1.2):
])
OVS_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([ofproto - set-field flow_mod commands (OF1.2)])
OVS_VSWITCHD_START
AT_CHECK([ovs-ofctl -O OpenFlow12 add-flow br0 ipv6,table=1,in_port=3,actions=drop])
AT_CHECK([ovs-ofctl -O OpenFlow12 add-flow br0 ipv6,table=1,in_port=3,actions=set_field:fe80:0123:4567:890a:a6ba:dbff:fefe:59fa-\>ipv6_src])
AT_CHECK([ovs-ofctl -O OpenFlow12 add-flow br0 icmp6,icmp_type=136,table=1,in_port=3,actions=set_field:fe80:8675:3097:890a:a6ba:dbff:f00d:59fa-\>nd_target,set_field:cc:dd:ee:ff:00:11-\>nd_tll])
AT_CHECK([ovs-ofctl -O OpenFlow12 dump-flows br0 | ofctl_strip | sort], [0], [dnl
 table=1, icmp6,in_port=3,icmp_type=136 actions=set_field:fe80:8675:3097:890a:a6ba:dbff:f00d:59fa->nd_target,set_field:cc:dd:ee:ff:00:11->nd_tll
 table=1, ipv6,in_port=3 actions=set_field:fe80:123:4567:890a:a6ba:dbff:fefe:59fa->ipv6_src
OFPST_FLOW reply (OF1.2):
])
OVS_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([ofproto - dump flows with cookie])
OVS_VSWITCHD_START
AT_CHECK([ovs-ofctl add-flow br0 cookie=0x1,in_port=1,actions=1])
AT_CHECK([ovs-ofctl add-flow br0 cookie=0x2,in_port=2,actions=1])
AT_CHECK([ovs-ofctl add-flow br0 cookie=0x3,in_port=3,actions=1])
AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort], [0], [dnl
 cookie=0x1, in_port=1 actions=output:1
 cookie=0x2, in_port=2 actions=output:1
 cookie=0x3, in_port=3 actions=output:1
NXST_FLOW reply:
])
AT_CHECK([ovs-ofctl dump-aggregate br0 table=0 | strip_xids], [0], [dnl
NXST_AGGREGATE reply: packet_count=0 byte_count=0 flow_count=3
])
AT_CHECK([ovs-ofctl dump-flows br0 cookie=0x3/-1 | ofctl_strip | sort], [0], [dnl
 cookie=0x3, in_port=3 actions=output:1
NXST_FLOW reply:
])
AT_CHECK([ovs-ofctl dump-aggregate br0 cookie=0x3/-1 | strip_xids], [0], [dnl
NXST_AGGREGATE reply: packet_count=0 byte_count=0 flow_count=1
])
OVS_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([ofproto - mod flow with cookie change (OpenFlow 1.0)])
OVS_VSWITCHD_START
AT_CHECK([ovs-ofctl -F openflow10 add-flow br0 cookie=0x1,in_port=1,actions=1])
AT_CHECK([ovs-ofctl -F openflow10 dump-flows br0 | ofctl_strip | sort], [0], [dnl
 cookie=0x1, in_port=1 actions=output:1
OFPST_FLOW reply:
])

AT_CHECK([ovs-ofctl -F openflow10 mod-flows br0 cookie=0x2,in_port=1,actions=1])
AT_CHECK([ovs-ofctl -F openflow10 dump-flows br0 | ofctl_strip | sort], [0], [dnl
 cookie=0x2, in_port=1 actions=output:1
OFPST_FLOW reply:
])
OVS_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([ofproto - mod flow with cookie change (NXM)])
OVS_VSWITCHD_START
AT_CHECK([ovs-ofctl -F nxm add-flow br0 cookie=0x1,in_port=1,actions=1])
AT_CHECK([ovs-ofctl -F nxm dump-flows br0 | ofctl_strip | sort], [0], [dnl
 cookie=0x1, in_port=1 actions=output:1
NXST_FLOW reply:
])

AT_CHECK([ovs-ofctl -F nxm mod-flows br0 cookie=0x2,in_port=1,actions=1])
AT_CHECK([ovs-ofctl -F nxm dump-flows br0 | ofctl_strip | sort], [0], [dnl
 cookie=0x2, in_port=1 actions=output:1
NXST_FLOW reply:
])
OVS_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([ofproto - no mod flow with cookie change (OpenFlow 1.1)])
OVS_VSWITCHD_START
AT_CHECK([ovs-ofctl -O OpenFlow11 add-flow br0 cookie=0x1,in_port=1,actions=1])
AT_CHECK([ovs-ofctl -O OpenFlow11 dump-flows br0 | ofctl_strip | sort], [0], [dnl
 cookie=0x1, in_port=1 actions=output:1
OFPST_FLOW reply (OF1.1):
])
AT_CHECK([ovs-ofctl -O OpenFlow11 mod-flows br0 cookie=0x2,in_port=1,actions=1])
AT_CHECK([ovs-ofctl -O OpenFlow11 dump-flows br0 | ofctl_strip | sort], [0], [dnl
 cookie=0x1, in_port=1 actions=output:1
OFPST_FLOW reply (OF1.1):
])
OVS_VSWITCHD_STOP
AT_CLEANUP

dnl The OpenFlow 1.2 spec states that the cookie may not be modified
AT_SETUP([ofproto - no mod flow with cookie change (OpenFlow 1.2)])
OVS_VSWITCHD_START
AT_CHECK([ovs-ofctl -O OpenFlow12 add-flow br0 cookie=0x1,in_port=1,actions=1])
AT_CHECK([ovs-ofctl -O OpenFlow12 dump-flows br0 | ofctl_strip | sort], [0], [dnl
 cookie=0x1, in_port=1 actions=output:1
OFPST_FLOW reply (OF1.2):
])

AT_CHECK([ovs-ofctl -O OpenFlow12 mod-flows br0 cookie=0x2,in_port=1,actions=1])
AT_CHECK([ovs-ofctl -O OpenFlow12 dump-flows br0 | ofctl_strip | sort], [0], [dnl
 cookie=0x1, in_port=1 actions=output:1
OFPST_FLOW reply (OF1.2):
])
OVS_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([ofproto - mod flows based on cookie mask (OpenFlow 1.0)])
OVS_VSWITCHD_START
AT_CHECK([ovs-ofctl add-flow br0 cookie=0x1,in_port=1,actions=1])
AT_CHECK([ovs-ofctl add-flow br0 cookie=0x1,in_port=2,actions=1])
AT_CHECK([ovs-ofctl add-flow br0 cookie=0x2,in_port=3,actions=1])
AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort], [0], [dnl
 cookie=0x1, in_port=1 actions=output:1
 cookie=0x1, in_port=2 actions=output:1
 cookie=0x2, in_port=3 actions=output:1
NXST_FLOW reply:
])

AT_CHECK([ovs-ofctl -F nxm mod-flows br0 cookie=0x1/0xff,actions=4])
AT_CHECK([ovs-ofctl -F nxm dump-flows br0 | ofctl_strip | sort], [0], [dnl
 cookie=0x1, in_port=1 actions=output:4
 cookie=0x1, in_port=2 actions=output:4
 cookie=0x2, in_port=3 actions=output:1
NXST_FLOW reply:
])
OVS_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([ofproto - mod flows based on cookie mask (OpenFlow 1.1)])
OVS_VSWITCHD_START
AT_CHECK([ovs-ofctl -O OpenFlow11 add-flow br0 cookie=0x1,in_port=1,actions=1])
AT_CHECK([ovs-ofctl -O OpenFlow11 add-flow br0 cookie=0x1,in_port=2,actions=1])
AT_CHECK([ovs-ofctl -O OpenFlow11 add-flow br0 cookie=0x2,in_port=3,actions=1])
AT_CHECK([ovs-ofctl -O OpenFlow11 dump-flows br0 | ofctl_strip | sort], [0], [dnl
 cookie=0x1, in_port=1 actions=output:1
 cookie=0x1, in_port=2 actions=output:1
 cookie=0x2, in_port=3 actions=output:1
OFPST_FLOW reply (OF1.1):
])

AT_CHECK([ovs-ofctl -O OpenFlow11 mod-flows br0 cookie=0x1/0xff,actions=4])
AT_CHECK([ovs-ofctl -O OpenFlow11 dump-flows br0 | ofctl_strip | sort], [0], [dnl
 cookie=0x1, in_port=1 actions=output:4
 cookie=0x1, in_port=2 actions=output:4
 cookie=0x2, in_port=3 actions=output:1
OFPST_FLOW reply (OF1.1):
])
OVS_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([ofproto - mod flows based on cookie mask (OpenFlow 1.2)])
OVS_VSWITCHD_START
AT_CHECK([ovs-ofctl -O OpenFlow12 add-flow br0 cookie=0x1,in_port=1,actions=1])
AT_CHECK([ovs-ofctl -O OpenFlow12 add-flow br0 cookie=0x1,in_port=2,actions=1])
AT_CHECK([ovs-ofctl -O OpenFlow12 add-flow br0 cookie=0x2,in_port=3,actions=1])
AT_CHECK([ovs-ofctl -O OpenFlow12 dump-flows br0 | ofctl_strip | sort], [0], [dnl
 cookie=0x1, in_port=1 actions=output:1
 cookie=0x1, in_port=2 actions=output:1
 cookie=0x2, in_port=3 actions=output:1
OFPST_FLOW reply (OF1.2):
])

AT_CHECK([ovs-ofctl -O OpenFlow12 mod-flows br0 cookie=0x1/0xff,actions=4])
AT_CHECK([ovs-ofctl -O OpenFlow12 dump-flows br0 | ofctl_strip | sort], [0], [dnl
 cookie=0x1, in_port=1 actions=output:4
 cookie=0x1, in_port=2 actions=output:4
 cookie=0x2, in_port=3 actions=output:1
OFPST_FLOW reply (OF1.2):
])
OVS_VSWITCHD_STOP
AT_CLEANUP

dnl The OpenFlow 1.2 spec states that the cookie may not be modified
AT_SETUP([ofproto - mod flows based on cookie mask with cookie change])
OVS_VSWITCHD_START
AT_CHECK([ovs-ofctl add-flow br0 cookie=0x1,in_port=1,actions=1])
AT_CHECK([ovs-ofctl add-flow br0 cookie=0x1,in_port=2,actions=1])
AT_CHECK([ovs-ofctl add-flow br0 cookie=0x2,in_port=3,actions=1])
AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort], [0], [dnl
 cookie=0x1, in_port=1 actions=output:1
 cookie=0x1, in_port=2 actions=output:1
 cookie=0x2, in_port=3 actions=output:1
NXST_FLOW reply:
])

AT_CHECK([ovs-ofctl -F nxm mod-flows br0 cookie=1/-1,cookie=4,actions=4])
AT_CHECK([ovs-ofctl -F nxm dump-flows br0 | ofctl_strip | sort], [0], [dnl
 cookie=0x2, in_port=3 actions=output:1
 cookie=0x4, in_port=1 actions=output:4
 cookie=0x4, in_port=2 actions=output:4
NXST_FLOW reply:
])
OVS_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([ofproto - mod flow with cookie miss (mask==0) - NXM])
OVS_VSWITCHD_START
AT_CHECK([ovs-ofctl -F nxm mod-flows br0 in_port=1,actions=1])
AT_CHECK([ovs-ofctl -F nxm dump-flows br0 | ofctl_strip | sort], [0], [dnl
 in_port=1 actions=output:1
NXST_FLOW reply:
])
OVS_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([ofproto - mod flow with cookie miss (mask==0) - OF1.1])
OVS_VSWITCHD_START
AT_CHECK([ovs-ofctl -O openflow11 mod-flows br0 in_port=1,actions=1])
AT_CHECK([ovs-ofctl -O openflow11 dump-flows br0 | ofctl_strip | sort], [0], [dnl
 in_port=1 actions=output:1
OFPST_FLOW reply (OF1.1):
])
OVS_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([ofproto - mod flow with cookie miss (mask==0) - OF1.2])
OVS_VSWITCHD_START
AT_CHECK([ovs-ofctl -O openflow12 mod-flows br0 in_port=1,actions=1])
AT_CHECK([ovs-ofctl -O openflow12 dump-flows br0 | ofctl_strip | sort], [0], [dnl
OFPST_FLOW reply (OF1.2):
])
OVS_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([ofproto - mod flow with cookie miss (mask!=0) - NXM])
OVS_VSWITCHD_START
AT_CHECK([ovs-ofctl -F nxm mod-flows br0 cookie=1/1,in_port=1,actions=1])
AT_CHECK([ovs-ofctl -F nxm dump-flows br0 | ofctl_strip | sort], [0], [dnl
NXST_FLOW reply:
])
OVS_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([ofproto - mod flow with cookie miss (mask!=0) - OF1.1])
OVS_VSWITCHD_START
AT_CHECK([ovs-ofctl -O openflow11 mod-flows br0 cookie=1/1,in_port=1,actions=1])
AT_CHECK([ovs-ofctl -O openflow11 dump-flows br0 | ofctl_strip | sort], [0], [dnl
OFPST_FLOW reply (OF1.1):
])
OVS_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([ofproto - mod flow with cookie miss (mask!=0) - OF1.2])
OVS_VSWITCHD_START
AT_CHECK([ovs-ofctl -O openflow12 mod-flows br0 cookie=1/1,in_port=1,actions=1])
AT_CHECK([ovs-ofctl -O openflow12 dump-flows br0 | ofctl_strip | sort], [0], [dnl
OFPST_FLOW reply (OF1.2):
])
OVS_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([ofproto - del flows with cookies])
OVS_VSWITCHD_START
AT_CHECK([ovs-ofctl add-flow br0 cookie=0x1,in_port=1,actions=1])
AT_CHECK([ovs-ofctl add-flow br0 cookie=0x2,in_port=2,actions=1])
AT_CHECK([ovs-ofctl add-flow br0 cookie=0x3,in_port=3,actions=1])
AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort], [0], [dnl
 cookie=0x1, in_port=1 actions=output:1
 cookie=0x2, in_port=2 actions=output:1
 cookie=0x3, in_port=3 actions=output:1
NXST_FLOW reply:
])

AT_CHECK([ovs-ofctl del-flows br0])
AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort], [0], [dnl
NXST_FLOW reply:
])
OVS_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([ofproto - del flows based on cookie])
OVS_VSWITCHD_START
AT_CHECK([ovs-ofctl add-flow br0 cookie=0x1,in_port=1,actions=1])
AT_CHECK([ovs-ofctl add-flow br0 cookie=0x2,in_port=2,actions=1])
AT_CHECK([ovs-ofctl add-flow br0 cookie=0x3,in_port=3,actions=1])
AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort], [0], [dnl
 cookie=0x1, in_port=1 actions=output:1
 cookie=0x2, in_port=2 actions=output:1
 cookie=0x3, in_port=3 actions=output:1
NXST_FLOW reply:
])

AT_CHECK([ovs-ofctl del-flows br0 cookie=0x3/-1])
AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort], [0], [dnl
 cookie=0x1, in_port=1 actions=output:1
 cookie=0x2, in_port=2 actions=output:1
NXST_FLOW reply:
])
OVS_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([ofproto - del flows based on cookie mask])
OVS_VSWITCHD_START
AT_CHECK([ovs-ofctl add-flow br0 cookie=0x1,in_port=1,actions=1])
AT_CHECK([ovs-ofctl add-flow br0 cookie=0x2,in_port=2,actions=1])
AT_CHECK([ovs-ofctl add-flow br0 cookie=0x3,in_port=3,actions=1])
AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort], [0], [dnl
 cookie=0x1, in_port=1 actions=output:1
 cookie=0x2, in_port=2 actions=output:1
 cookie=0x3, in_port=3 actions=output:1
NXST_FLOW reply:
])
AT_CHECK([ovs-ofctl del-flows br0 cookie=0x3/0x1])
AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort], [0], [dnl
 cookie=0x2, in_port=2 actions=output:1
NXST_FLOW reply:
])
OVS_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([ofproto - del flows based on table id (NXM)])
OVS_VSWITCHD_START
AT_CHECK([ovs-ofctl add-flow br0 cookie=0x1,in_port=1,actions=1])
AT_CHECK([ovs-ofctl add-flow br0 cookie=0x2,in_port=2,table=1,actions=1])
AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort], [0], [dnl
 cookie=0x1, in_port=1 actions=output:1
 cookie=0x2, table=1, in_port=2 actions=output:1
NXST_FLOW reply:
])
AT_CHECK([ovs-ofctl del-flows br0 table=0])
AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort], [0], [dnl
 cookie=0x2, table=1, in_port=2 actions=output:1
NXST_FLOW reply:
])
AT_CHECK([ovs-ofctl del-flows br0 table=1])
AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort], [0], [dnl
NXST_FLOW reply:
])
AT_CHECK([ovs-ofctl add-flow br0 cookie=0x1,in_port=1,actions=1])
AT_CHECK([ovs-ofctl add-flow br0 cookie=0x2,in_port=2,table=1,actions=1])
AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort], [0], [dnl
 cookie=0x1, in_port=1 actions=output:1
 cookie=0x2, table=1, in_port=2 actions=output:1
NXST_FLOW reply:
])
AT_CHECK([ovs-ofctl del-flows br0])
AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort], [0], [dnl
NXST_FLOW reply:
])
OVS_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([ofproto - del flows based on table id (OpenFlow 1.1)])
OVS_VSWITCHD_START
AT_CHECK([ovs-ofctl -O OpenFlow11 add-flow br0 cookie=0x1,in_port=1,actions=1])
AT_CHECK([ovs-ofctl -O OpenFlow11 add-flow br0 cookie=0x2,in_port=2,table=1,actions=1])
AT_CHECK([ovs-ofctl -O OpenFlow11 dump-flows br0 | ofctl_strip | sort], [0], [dnl
 cookie=0x1, in_port=1 actions=output:1
 cookie=0x2, table=1, in_port=2 actions=output:1
OFPST_FLOW reply (OF1.1):
])
AT_CHECK([ovs-ofctl -O OpenFlow11 del-flows br0 table=0])
AT_CHECK([ovs-ofctl -O OpenFlow11 dump-flows br0 | ofctl_strip | sort], [0], [dnl
 cookie=0x2, table=1, in_port=2 actions=output:1
OFPST_FLOW reply (OF1.1):
])
AT_CHECK([ovs-ofctl -O OpenFlow11 del-flows br0 table=1])
AT_CHECK([ovs-ofctl -O OpenFlow11 dump-flows br0 | ofctl_strip | sort], [0], [dnl
OFPST_FLOW reply (OF1.1):
])
AT_CHECK([ovs-ofctl -O OpenFlow11 add-flow br0 cookie=0x1,in_port=1,actions=1])
AT_CHECK([ovs-ofctl -O OpenFlow11 add-flow br0 cookie=0x2,in_port=2,table=1,actions=1])
AT_CHECK([ovs-ofctl -O OpenFlow11 dump-flows br0 | ofctl_strip | sort], [0], [dnl
 cookie=0x1, in_port=1 actions=output:1
 cookie=0x2, table=1, in_port=2 actions=output:1
OFPST_FLOW reply (OF1.1):
])
AT_CHECK([ovs-ofctl -O OpenFlow11 del-flows br0])
AT_CHECK([ovs-ofctl -O OpenFlow11 dump-flows br0 | ofctl_strip], [0], [dnl
OFPST_FLOW reply (OF1.1):
 cookie=0x2, table=1, in_port=2 actions=output:1
])
OVS_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([ofproto - del flows based on table id (OpenFlow 1.2)])
OVS_VSWITCHD_START
AT_CHECK([ovs-ofctl -O OpenFlow12 add-flow br0 cookie=0x1,in_port=1,actions=1])
AT_CHECK([ovs-ofctl -O OpenFlow12 add-flow br0 cookie=0x2,in_port=2,table=1,actions=1])
AT_CHECK([ovs-ofctl -O OpenFlow12 dump-flows br0 | ofctl_strip | sort], [0], [dnl
 cookie=0x1, in_port=1 actions=output:1
 cookie=0x2, table=1, in_port=2 actions=output:1
OFPST_FLOW reply (OF1.2):
])
AT_CHECK([ovs-ofctl -O OpenFlow12 del-flows br0 table=0])
AT_CHECK([ovs-ofctl -O OpenFlow12 dump-flows br0 | ofctl_strip | sort], [0], [dnl
 cookie=0x2, table=1, in_port=2 actions=output:1
OFPST_FLOW reply (OF1.2):
])
AT_CHECK([ovs-ofctl -O OpenFlow12 del-flows br0 table=1])
AT_CHECK([ovs-ofctl -O OpenFlow12 dump-flows br0 | ofctl_strip | sort], [0], [dnl
OFPST_FLOW reply (OF1.2):
])
AT_CHECK([ovs-ofctl -O OpenFlow12 add-flow br0 cookie=0x1,in_port=1,actions=1])
AT_CHECK([ovs-ofctl -O OpenFlow12 add-flow br0 cookie=0x2,in_port=2,table=1,actions=1])
AT_CHECK([ovs-ofctl -O OpenFlow12 dump-flows br0 | ofctl_strip | sort], [0], [dnl
 cookie=0x1, in_port=1 actions=output:1
 cookie=0x2, table=1, in_port=2 actions=output:1
OFPST_FLOW reply (OF1.2):
])
AT_CHECK([ovs-ofctl -O OpenFlow12 del-flows br0])
AT_CHECK([ovs-ofctl -O OpenFlow12 dump-flows br0 | ofctl_strip | sort], [0], [dnl
OFPST_FLOW reply (OF1.2):
])
OVS_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([ofproto - flow_mod with out_port matching (OpenFlow 1.0)])
OVS_VSWITCHD_START
AT_DATA([flows.txt], [dnl
 in_port=1 actions=output:2
 in_port=2 actions=output:1,output:2,output:3
 in_port=3 actions=output:3,output:1,output:2
 in_port=4 actions=drop
 in_port=5 actions=output:3
 in_port=6 actions=output:1
])
AT_CHECK([ovs-ofctl -F openflow10 add-flows br0 flows.txt])
(cat flows.txt; echo 'OFPST_FLOW reply:') > expout
AT_CHECK([ovs-ofctl -F openflow10 dump-flows br0 | ofctl_strip | sort], [0],
  [expout])

(grep 'output:2' flows.txt; echo 'OFPST_FLOW reply:') > expout
AT_CHECK([ovs-ofctl -F openflow10 dump-flows br0 out_port=2 | ofctl_strip | sort], [0], [expout])

AT_CHECK([ovs-ofctl -F openflow10 del-flows br0 out_port=2])
(grep -v 'output:2' flows.txt; echo 'OFPST_FLOW reply:') > expout
AT_CHECK([ovs-ofctl -F openflow10 dump-flows br0 | ofctl_strip | sort], [0],
  [expout])

AT_CHECK([ovs-ofctl -F openflow10 del-flows br0 out_port=3])
(grep -v 'output:[[23]]' flows.txt; echo 'OFPST_FLOW reply:') > expout
AT_CHECK([ovs-ofctl -F openflow10 dump-flows br0 | ofctl_strip | sort], [0],
  [expout])

AT_CHECK([ovs-ofctl -F openflow10 del-flows br0 out_port=1])
(grep -v 'output:[[123]]' flows.txt; echo 'OFPST_FLOW reply:') > expout
AT_CHECK([ovs-ofctl -F openflow10 dump-flows br0 | ofctl_strip | sort], [0],
  [expout])

OVS_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([ofproto - flow_mod with out_port matching (OpenFlow 1.1)])
OVS_VSWITCHD_START
AT_DATA([flows.txt], [dnl
 in_port=1 actions=output:2
 in_port=2 actions=output:1,write_actions(output:2,output:3)
 in_port=3 actions=output:3,output:1,write_actions(output:2)
 in_port=4 actions=drop
 in_port=5 actions=write_actions(output:3)
 in_port=6 actions=output:1
])
AT_CHECK([ovs-ofctl -O OpenFlow11 add-flows br0 flows.txt])
(cat flows.txt; echo 'OFPST_FLOW reply (OF1.1):') > expout
AT_CHECK([ovs-ofctl -O OpenFlow11 dump-flows br0 | ofctl_strip | sort], [0],
  [expout])

(grep 'output:2' flows.txt; echo 'OFPST_FLOW reply (OF1.1):') > expout
AT_CHECK([ovs-ofctl -O OpenFlow11 dump-flows br0 out_port=2 | ofctl_strip | sort], [0], [expout])

AT_CHECK([ovs-ofctl -O OpenFlow11 del-flows br0 out_port=2])
(grep -v 'output:2' flows.txt; echo 'OFPST_FLOW reply (OF1.1):') > expout
AT_CHECK([ovs-ofctl -O OpenFlow11 dump-flows br0 | ofctl_strip | sort], [0],
  [expout])

AT_CHECK([ovs-ofctl -O OpenFlow11 del-flows br0 out_port=3])
(grep -v 'output:[[23]]' flows.txt; echo 'OFPST_FLOW reply (OF1.1):') > expout
AT_CHECK([ovs-ofctl -O OpenFlow11 dump-flows br0 | ofctl_strip | sort], [0],
  [expout])

AT_CHECK([ovs-ofctl -O OpenFlow11 del-flows br0 out_port=1])
(grep -v 'output:[[123]]' flows.txt; echo 'OFPST_FLOW reply (OF1.1):') > expout
AT_CHECK([ovs-ofctl -O OpenFlow11 dump-flows br0 | ofctl_strip | sort], [0],
  [expout])

OVS_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([ofproto - flow_mod with out_group matching (OpenFlow 1.1)])
OVS_VSWITCHD_START
AT_DATA([groups.txt], [dnl
group_id=1,type=all,bucket=output:10
group_id=2,type=all,bucket=output:10
group_id=3,type=all,bucket=output:10
])
AT_CHECK([ovs-ofctl -O OpenFlow11 add-groups br0 groups.txt])
AT_DATA([flows.txt], [dnl
 in_port=1 actions=group:2,output:5
 in_port=2 actions=group:1,write_actions(group:2,group:3,output:6)
 in_port=3 actions=group:3,group:1,write_actions(group:2,output:3)
 in_port=4 actions=output:4
 in_port=5 actions=write_actions(output:4,group:3)
 in_port=6 actions=group:1
])
AT_CHECK([ovs-ofctl -O OpenFlow11 add-flows br0 flows.txt])
(cat flows.txt; echo 'OFPST_FLOW reply (OF1.1):') > expout
AT_CHECK([ovs-ofctl -O OpenFlow11 dump-flows br0 | ofctl_strip | sort], [0],
  [expout])

(grep 'output:3' flows.txt | grep 'group:2'; echo 'OFPST_FLOW reply (OF1.1):') > expout
AT_CHECK([ovs-ofctl -O OpenFlow11 dump-flows br0 out_port=3,out_group=2 | ofctl_strip | sort], [0], [expout])

AT_CHECK([ovs-ofctl -O OpenFlow11 del-flows br0 out_group=2])
(grep -v 'group:2' flows.txt; echo 'OFPST_FLOW reply (OF1.1):') > expout
AT_CHECK([ovs-ofctl -O OpenFlow11 dump-flows br0 | ofctl_strip | sort], [0],
  [expout])

AT_CHECK([ovs-ofctl -O OpenFlow11 del-flows br0 out_group=3])
(grep -v 'group:[[23]]' flows.txt; echo 'OFPST_FLOW reply (OF1.1):') > expout
AT_CHECK([ovs-ofctl -O OpenFlow11 dump-flows br0 | ofctl_strip | sort], [0],
  [expout])

AT_CHECK([ovs-ofctl -O OpenFlow11 del-flows br0 out_group=1])
(grep -v 'group:[[123]]' flows.txt; echo 'OFPST_FLOW reply (OF1.1):') > expout
AT_CHECK([ovs-ofctl -O OpenFlow11 dump-flows br0 | ofctl_strip | sort], [0],
  [expout])

OVS_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([ofproto - bundle flow_mod with out group matching (OpenFlow 1.4)])
OVS_VSWITCHD_START
AT_DATA([bundle.txt], [dnl
group group_id=1,type=all,bucket=output:10
group group_id=2,type=all,bucket=output:10
group group_id=3,type=all,bucket=output:10
flow in_port=1 actions=group:2,output:5
flow in_port=2 actions=group:1,write_actions(group:2,group:3,output:6)
flow in_port=3 actions=group:3,group:1,write_actions(group:2,output:3)
flow in_port=4 actions=output:4
flow in_port=5 actions=write_actions(output:4,group:3)
flow in_port=6 actions=group:1
])
AT_CHECK([ovs-ofctl bundle br0 bundle.txt])

# for checking
AT_DATA([flows.txt], [dnl
 in_port=1 actions=group:2,output:5
 in_port=2 actions=group:1,write_actions(group:2,group:3,output:6)
 in_port=3 actions=group:3,group:1,write_actions(group:2,output:3)
 in_port=4 actions=output:4
 in_port=5 actions=write_actions(output:4,group:3)
 in_port=6 actions=group:1
])

(cat flows.txt; echo 'OFPST_FLOW reply (OF1.4):') > expout
AT_CHECK([ovs-ofctl -O OpenFlow14 dump-flows br0 | ofctl_strip | sort], [0],
  [expout])

(grep 'output:3' flows.txt | grep 'group:2'; echo 'OFPST_FLOW reply (OF1.4):') > expout
AT_CHECK([ovs-ofctl -O OpenFlow14 dump-flows br0 out_port=3,out_group=2 | ofctl_strip | sort], [0], [expout])

AT_CHECK([ovs-ofctl -O OpenFlow14 del-flows br0 out_group=2])
(grep -v 'group:2' flows.txt; echo 'OFPST_FLOW reply (OF1.4):') > expout
AT_CHECK([ovs-ofctl -O OpenFlow14 dump-flows br0 | ofctl_strip | sort], [0],
  [expout])

AT_CHECK([ovs-ofctl -O OpenFlow14 del-flows br0 out_group=3])
(grep -v 'group:[[23]]' flows.txt; echo 'OFPST_FLOW reply (OF1.4):') > expout
AT_CHECK([ovs-ofctl -O OpenFlow14 dump-flows br0 | ofctl_strip | sort], [0],
  [expout])

AT_CHECK([ovs-ofctl -O OpenFlow14 del-flows br0 out_group=1])
(grep -v 'group:[[123]]' flows.txt; echo 'OFPST_FLOW reply (OF1.4):') > expout
AT_CHECK([ovs-ofctl -O OpenFlow14 dump-flows br0 | ofctl_strip | sort], [0],
  [expout])

OVS_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([ofproto - bundle packet-out (OpenFlow 1.4)])
OVS_VSWITCHD_START

ovs-ofctl del-flows br0
ovs-ofctl add-flow br0 priority=0,actions=drop

# Start a monitor listening for packet-ins.
AT_CHECK([ovs-ofctl -P standard monitor br0 --detach --no-chdir --pidfile])
ovs-appctl -t ovs-ofctl ofctl/send 0109000c0123456700000080
ovs-appctl -t ovs-ofctl ofctl/barrier
ovs-appctl -t ovs-ofctl ofctl/set-output-file monitor.log
AT_CAPTURE_FILE([monitor.log])

# This bundle adds a group, a flow using that group and then a
# packet-out that needs them both.  Finally the bundle deletes all
# groups, which also deletes the flow, leaving only the drop flow in
# the table.  If this works properly, the packet-out should get
# translated and processed before the flow disappears.  Also, if the
# bundle were to fail, the packet-in should not get executed.
AT_DATA([bundle.txt], [dnl
group group_id=1,type=all,bucket=output:controller
flow in_port=6 actions=group:1
packet-out in_port=6, packet=0001020304050010203040501234 actions=table
group delete
])
AT_CHECK([ovs-ofctl bundle br0 bundle.txt])

# Verify that only the drop flow remains.
AT_CHECK([ovs-ofctl -O OpenFlow14 dump-flows br0 | ofctl_strip | sort], [0],
  [ reset_counts priority=0 actions=drop
OFPST_FLOW reply (OF1.4):
])

# Verify that the packet-in was received via controller action.
AT_CHECK([sed 's/ (xid=0x[[1-9a-fA-F]][[0-9a-fA-F]]*)//' monitor.log], [0],
  [OFPT_PACKET_IN (xid=0x0): total_len=14 in_port=6 (via action) data_len=14 (unbuffered)
vlan_tci=0x0000,dl_src=00:10:20:30:40:50,dl_dst=00:01:02:03:04:05,dl_type=0x1234
])

OVS_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([ofproto - bundle packet-out, failing bundle commit (OpenFlow 1.4)])
OVS_VSWITCHD_START

ovs-ofctl del-flows br0
ovs-ofctl add-flow br0 priority=0,actions=drop

# Start a monitor listening for packet-ins.
AT_CHECK([ovs-ofctl -P standard monitor br0 --detach --no-chdir --pidfile])
ovs-appctl -t ovs-ofctl ofctl/send 0109000c0123456700000080
ovs-appctl -t ovs-ofctl ofctl/barrier
ovs-appctl -t ovs-ofctl ofctl/set-output-file monitor.log
AT_CAPTURE_FILE([monitor.log])

# This bundle adds a flow using that group and then a packet-out that
# needs them both.  Finally the bundle adds another flow that referes
# to a non-existing group, causing the bundle to fail, and the
# packet-in should not get executed.
AT_DATA([bundle.txt], [dnl
group group_id=1,type=all,bucket=output:controller
flow in_port=6 actions=group:1
packet-out in_port=6, packet=0001020304050010203040501234 actions=table
flow in_port=7 actions=group:2
])
AT_CHECK([ovs-ofctl bundle br0 bundle.txt 2>&1 | sed '/talking to/,$d' | strip_xids], [], [dnl
Error OFPBAC_BAD_OUT_GROUP for: OFPT_FLOW_MOD (OF1.4): ADD in_port=7 actions=group:2
Error OFPBFC_MSG_FAILED for: OFPT_BUNDLE_CONTROL (OF1.4):
 bundle_id=0 type=COMMIT_REQUEST flags=atomic ordered
])

# Verify that only the drop flow remains.
AT_CHECK([ovs-ofctl -O OpenFlow14 dump-flows br0 | ofctl_strip | sort], [0],
  [ reset_counts priority=0 actions=drop
OFPST_FLOW reply (OF1.4):
])

# Verify that the packet-in was NOT received via controller action.
AT_CHECK([strip_xids < monitor.log], [0], [])

OVS_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([ofproto - bundle packet-out makes bundle commit to fail(OpenFlow 1.4)])
OVS_VSWITCHD_START

ovs-ofctl del-flows br0
ovs-ofctl add-flow br0 priority=0,actions=drop

# Start a monitor listening for packet-ins.
AT_CHECK([ovs-ofctl -P standard monitor br0 --detach --no-chdir --pidfile])
ovs-appctl -t ovs-ofctl ofctl/send 0109000c0123456700000080
ovs-appctl -t ovs-ofctl ofctl/barrier
ovs-appctl -t ovs-ofctl ofctl/set-output-file monitor.log
AT_CAPTURE_FILE([monitor.log])

# This bundle adds a flow using that group and then a packet-out that
# needs them both.  Finally the bundle adds another flow that referes
# to a non-existing group, causing the bundle to fail, and the
# packet-in should not get executed.
AT_DATA([bundle.txt], [dnl
group group_id=1,type=all,bucket=output:controller
flow in_port=6 actions=group:1
packet-out in_port=6, packet=0001020304050010203040501234 actions=table
packet-out in_port=6, packet=0001020304050010203040501234 actions=group:2
])
AT_CHECK([ovs-ofctl bundle br0 bundle.txt 2>&1 | sed '/talking to/,$d' | strip_xids], [], [dnl
Error OFPBAC_BAD_OUT_GROUP for: OFPT_PACKET_OUT (OF1.4): in_port=6 actions=group:2 data_len=14
vlan_tci=0x0000,dl_src=00:10:20:30:40:50,dl_dst=00:01:02:03:04:05,dl_type=0x1234
Error OFPBFC_MSG_FAILED for: OFPT_BUNDLE_CONTROL (OF1.4):
 bundle_id=0 type=COMMIT_REQUEST flags=atomic ordered
])

# Verify that only the drop flow remains.
AT_CHECK([ovs-ofctl -O OpenFlow14 dump-flows br0 | ofctl_strip | sort], [0],
  [ reset_counts priority=0 actions=drop
OFPST_FLOW reply (OF1.4):
])

# Verify that the packet-in was NOT received via controller action.
AT_CHECK([strip_xids < monitor.log], [0], [])

OVS_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([ofproto - flow table configuration (OpenFlow 1.0)])
OVS_VSWITCHD_START
# Check the default configuration.
head_table() {
    printf 'OFPST_TABLE reply (xid=0x2):
  table 0%s:
    active=0, lookup=0, matched=0
    max_entries=1000000
    matching:
      exact match or wildcard: in_port eth_{src,dst,type} vlan_{vid,pcp} ip_{src,dst} nw_{proto,tos} tcp_{src,dst}

' "$1"
}
(head_table; echo '  tables 1...253: ditto') > expout
AT_CHECK([ovs-ofctl dump-tables br0], [0], [expout])
# Change the configuration.
AT_CHECK(
  [ovs-vsctl \
     -- --id=@t0 create Flow_Table name=main \
     -- --id=@t1 create Flow_Table flow-limit=1024 \
     -- set bridge br0 'flow_tables={1=@t1,0=@t0}' \
   | uuidfilt],
  [0], [<0>
<1>
])
# Check that the configuration was updated.
(head_table ' ("main")'; echo '  table 1:
    active=0, lookup=0, matched=0
    max_entries=1024
    (same matching)

  table 2:
    active=0, lookup=0, matched=0
    max_entries=1000000
    (same matching)
'; echo '  tables 3...253: ditto') > expout
AT_CHECK([ovs-ofctl dump-tables br0], [0], [expout])
OVS_VSWITCHD_STOP
AT_CLEANUP

dnl In-band and fail-open add "hidden rules" to table 0.  These rules shouldn't
dnl be visible to OpenFlow.  This test checks that "dump-flows" and
dnl "dump-tables" don't make them visible.
AT_SETUP([ofproto - hidden rules not in table stats])
# Use an IP address for a controller that won't actually exist: we
# want to create in-band rules but we do not want to actually connect
# to a controller (because that could mess about with our test).  The
# Class E range 240.0.0.0 - 255.255.255.255 seems like a good choice.
OVS_VSWITCHD_START([set-controller br0 tcp:240.0.0.1:6653])
for i in 1 2 3 4 5; do ovs-appctl time/warp 1000; done

# Check that no hidden flows are visible in OpenFlow.
AT_CHECK([ovs-ofctl dump-flows br0 | strip_xids], [0], [NXST_FLOW reply:
])

# Check that some hidden flows related to 240.0.0.1 are actually in table 0.
#
# We discard flows that mention table_id because we only want table 0 flows,
# which in OVS is implied by the absence of a table_id.
AT_CHECK([ovs-appctl bridge/dump-flows br0], [0], [stdout])
AT_CHECK([test `grep '240\.0\.0\.1' stdout | grep -v table_id= | wc -l` -gt 0])

# Check that dump-tables doesn't count the hidden flows.
head_table() {
    printf 'OFPST_TABLE reply:
  table 0:
    active=0, lookup=0, matched=0
    max_entries=1000000
    matching:
      exact match or wildcard: in_port eth_{src,dst,type} vlan_{vid,pcp} ip_{src,dst} nw_{proto,tos} tcp_{src,dst}

'
}
(head_table; echo '  tables 1...253: ditto') > expout
AT_CHECK([ovs-ofctl dump-tables br0 | strip_xids], [0], [expout])
OVS_VSWITCHD_STOP(["/240\.0\.0\.1/d"])
AT_CLEANUP

AT_SETUP([ofproto - flow table configuration (OpenFlow 1.2)])
OVS_VSWITCHD_START
# Check the default configuration.
head_table() {
    printf 'OFPST_TABLE reply (OF1.2) (xid=0x2):
  table 0%s:
    active=0, lookup=0, matched=0
    metadata: match=0xffffffffffffffff write=0xffffffffffffffff
    config=controller
    max_entries=1000000
    instructions (table miss and others):
      instructions: apply_actions clear_actions write_actions write_metadata goto_table
      Write-Actions and Apply-Actions features:
        actions: output group set_field strip_vlan push_vlan mod_nw_ttl dec_ttl set_mpls_ttl dec_mpls_ttl push_mpls pop_mpls set_queue
        supported on Set-Field: metadata in_port_oxm eth_{src,dst} vlan_{vid,pcp} mpls_{label,tc} ip_{src,dst} ipv6_{src,dst,label} ip_dscp nw_ecn arp_{op,spa,tpa,sha,tha} tcp_{src,dst} udp_{src,dst} sctp_{src,dst} icmp_{type,code} icmpv6_{type,code} nd_{target,sll,tll}
    matching:
      exact match or wildcard: metadata in_port_oxm eth_{src,dst,type} vlan_{vid,pcp} mpls_{label,tc} ip_{src,dst} ipv6_{src,dst,label} nw_proto ip_dscp nw_ecn arp_{op,spa,tpa,sha,tha} tcp_{src,dst} udp_{src,dst} sctp_{src,dst} icmp_{type,code} icmpv6_{type,code} nd_{target,sll,tll}

' "$1"
}
tail_table() {
    printf '  table 253:
    active=0, lookup=0, matched=0
    metadata: match=0xffffffffffffffff write=0xffffffffffffffff
    config=controller
    max_entries=1000000
    instructions (table miss and others):
      instructions: apply_actions clear_actions write_actions write_metadata
      (same actions)
    (same matching)
'
}
(head_table; printf '  tables 1...252: ditto\n\n'; tail_table) > expout
AT_CHECK([ovs-ofctl -O OpenFlow12 dump-tables br0], [0], [expout])
# Change the configuration.
AT_CHECK(
  [ovs-vsctl \
     -- --id=@t0 create Flow_Table name=main \
     -- --id=@t1 create Flow_Table flow-limit=1024 \
     -- set bridge br0 'flow_tables={1=@t1,0=@t0}' \
   | uuidfilt],
  [0], [<0>
<1>
])
# Check that the configuration was updated.
(head_table ' ("main")'; echo '  table 1:
    active=0, lookup=0, matched=0
    metadata: match=0xffffffffffffffff write=0xffffffffffffffff
    config=controller
    max_entries=1024
    (same instructions)
    (same matching)

  table 2:
    active=0, lookup=0, matched=0
    metadata: match=0xffffffffffffffff write=0xffffffffffffffff
    config=controller
    max_entries=1000000
    (same instructions)
    (same matching)
'; printf '  tables 3...252: ditto\n\n'; tail_table) > expout
AT_CHECK([ovs-ofctl -O OpenFlow12 dump-tables br0], [0], [expout])
OVS_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([ofproto - table features (OpenFlow 1.3)])
OVS_VSWITCHD_START
head_table () {
    printf '  table 0%s:
    metadata: match=0xffffffffffffffff write=0xffffffffffffffff
    max_entries=1000000
    instructions (table miss and others):
      next tables: 1-253
      instructions: meter apply_actions clear_actions write_actions write_metadata goto_table
      Write-Actions and Apply-Actions features:
        actions: output group set_field strip_vlan push_vlan mod_nw_ttl dec_ttl set_mpls_ttl dec_mpls_ttl push_mpls pop_mpls set_queue
        supported on Set-Field: tun_{id,src,dst,ipv6_{src,dst},flags,gbp_{id,flags},erspan_{idx,ver,dir,hwid},metadata0...metadata63} metadata in_{port,port_oxm} pkt_mark ct_{mark,label} reg0...reg15 xreg0...xreg7 xxreg0...xxreg3 eth_{src,dst} vlan_{tci,vid,pcp} mpls_{label,tc,ttl} ip_{src,dst} ipv6_{src,dst,label} nw_tos ip_dscp nw_{ecn,ttl} arp_{op,spa,tpa,sha,tha} tcp_{src,dst} udp_{src,dst} sctp_{src,dst} icmp_{type,code} icmpv6_{type,code} nd_{target,sll,tll,reserved,options_type} nsh_{flags,spi,si,c1...c4,ttl}
    matching:
      arbitrary mask: dp_hash tun_{id,src,dst,ipv6_{src,dst},flags,gbp_{id,flags},erspan_{idx,ver,dir,hwid},gtpu_{flags,msgtype},metadata0...metadata63} metadata pkt_mark ct_{state,mark,label,nw_{src,dst},ipv6_{src,dst},tp_{src,dst}} reg0...reg15 xreg0...xreg7 xxreg0...xxreg3 eth_{src,dst} vlan_{tci,vid} ip_{src,dst} ipv6_{src,dst,label} ip_frag arp_{spa,tpa,sha,tha} tcp_{src,dst,flags} udp_{src,dst} sctp_{src,dst} nd_{target,sll,tll} nsh_{flags,c1...c4}
      exact match or wildcard: recirc_id packet_type conj_id in_{port,port_oxm} actset_output ct_{zone,nw_proto} eth_type vlan_pcp mpls_{label,tc,bos,ttl} nw_{proto,tos} ip_dscp nw_{ecn,ttl} arp_op icmp_{type,code} icmpv6_{type,code} nd_{reserved,options_type} nsh_{mdtype,np,spi,si,ttl}

' "$1"
}
tail_tables() {
echo '  table 253:
    metadata: match=0xffffffffffffffff write=0xffffffffffffffff
    max_entries=1000000
    instructions (table miss and others):
      instructions: meter apply_actions clear_actions write_actions write_metadata
      (same actions)
    (same matching)
'
}
(head_table
 printf '  tables 1...252: ditto\n\n'
 tail_tables) > expout
AT_CHECK([ovs-ofctl -O OpenFlow13 dump-table-features br0], [0], [expout])
# Change the configuration.
AT_CHECK(
  [ovs-vsctl \
     -- --id=@t0 create Flow_Table name=main \
     -- --id=@t1 create Flow_Table flow-limit=1024 \
     -- set bridge br0 'flow_tables={1=@t1,0=@t0}' \
   | uuidfilt],
  [0], [<0>
<1>
])
# Check that the configuration was updated.
(head_table ' ("main")'
 echo '  table 1:
    metadata: match=0xffffffffffffffff write=0xffffffffffffffff
    max_entries=1024
    (same instructions)
    (same matching)

  table 2:
    metadata: match=0xffffffffffffffff write=0xffffffffffffffff
    max_entries=1000000
    (same instructions)
    (same matching)

  tables 3...252: ditto
'
 tail_tables) > expout
AT_CHECK([ovs-ofctl -O OpenFlow13 dump-table-features br0], [0], [expout])
OVS_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([ofproto - flow table names])
OVS_VSWITCHD_START
add_of_ports br0 1 2

# Set a table name via OpenFlow 1.3 and one via OpenFlow 1.5.
AT_CHECK([ovs-ofctl -O OpenFlow13 mod-table br0 0 name:xyzzy])
AT_CHECK([ovs-ofctl -O OpenFlow15 mod-table br0 1 name:quux])
AT_CHECK([ovs-ofctl -O OpenFlow15 dump-table-features br0 |grep '^  table'],
  [0], [dnl
  table 0 ("xyzzy"):
  table 1 ("quux"): ditto
  tables 2...252: ditto
  table 253:
])

# Set some table names via OVSDB.
AT_CHECK(
  [ovs-vsctl \
     -- --id=@t0 create Flow_Table name=zero \
     -- --id=@t1 create Flow_Table name=one \
     -- --id=@t2 create Flow_Table name=two \
     -- set bridge br0 'flow_tables={0=@t0,1=@t1,2=@t2}' \
   | uuidfilt],
  [0], [<0>
<1>
<2>
])
AT_CHECK([ovs-ofctl -O OpenFlow15 dump-table-features br0 |grep '^  table'],
  [0], [dnl
  table 0 ("zero"):
  table 1 ("one"): ditto
  table 2 ("two"): ditto
  tables 3...252: ditto
  table 253:
])

# Check that flow table parsing and dumping uses the names.
AT_DATA([flows.txt], [dnl
table=zero in_port=p2 actions=p1,resubmit(,one)
table=one,in_port=p1,ip,actions=ct(table=two)
table=one,in_port=p1,arp,actions=goto_table(two)
])
AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
AT_CHECK([ovs-ofctl --names --no-stats dump-flows br0], [0], [dnl
 table=zero, in_port=p2 actions=output:p1,resubmit(,one)
 table=one, ip,in_port=p1 actions=ct(table=two)
 table=one, arp,in_port=p1 actions=resubmit(,two)
])
AT_CHECK([ovs-ofctl --no-names --no-stats dump-flows br0], [0], [dnl
 in_port=2 actions=output:1,resubmit(,1)
 table=1, ip,in_port=1 actions=ct(table=2)
 table=1, arp,in_port=1 actions=resubmit(,2)
])

# Setting the same table names via OpenFlow 1.3 or OpenFlow 1.5 is a no-op.
AT_CHECK([ovs-ofctl -O OpenFlow13 mod-table br0 0 name:zero])
AT_CHECK([ovs-ofctl -O OpenFlow15 mod-table br0 1 name:one])
AT_CHECK([ovs-ofctl -O OpenFlow15 dump-table-features br0 |grep '^  table'],
  [0], [dnl
  table 0 ("zero"):
  table 1 ("one"): ditto
  table 2 ("two"): ditto
  tables 3...252: ditto
  table 253:
])

# Setting different tables names via OpenFlow 1.3 or OpenFlow 1.5 yield errors.
AT_CHECK([ovs-ofctl -O OpenFlow13 mod-table br0 0 name:xyzzy], 1, [], [stderr])
AT_CHECK([head -1 stderr], [0], [OFPT_ERROR (OF1.3) (xid=0x5): OFPTFFC_EPERM
])
AT_CHECK([ovs-ofctl -O OpenFlow15 mod-table br0 1 name:quux], 1, [], [stderr])
AT_CHECK([head -1 stderr], [0], [OFPT_ERROR (OF1.5) (xid=0x5): OFPTFFC_EPERM
])

# But we can still set table names for those not set via OVSDB.
AT_CHECK([ovs-ofctl -O OpenFlow13 mod-table br0 3 name:three])
AT_CHECK([ovs-ofctl -O OpenFlow15 dump-table-features br0 |grep '^  table'],
  [0], [dnl
  table 0 ("zero"):
  table 1 ("one"): ditto
  table 2 ("two"): ditto
  table 3 ("three"): ditto
  tables 4...252: ditto
  table 253:
])

# Unsetting names via OVSDB then setting them via OpenFlow works too.
AT_CHECK([ovs-vsctl remove bridge br0 Flow_Table 2])
AT_CHECK([ovs-ofctl -O OpenFlow15 dump-table-features br0 |grep '^  table'],
  [0], [dnl
  table 0 ("zero"):
  table 1 ("one"): ditto
  table 2: ditto
  table 3 ("three"): ditto
  tables 4...252: ditto
  table 253:
])
AT_CHECK([ovs-ofctl -O OpenFlow13 mod-table br0 2 name:foobar])
AT_CHECK([ovs-ofctl -O OpenFlow15 dump-table-features br0 |grep '^  table'],
  [0], [dnl
  table 0 ("zero"):
  table 1 ("one"): ditto
  table 2 ("foobar"): ditto
  table 3 ("three"): ditto
  tables 4...252: ditto
  table 253:
])

# We can clear names via OpenFlow, at least if they were set that way.
AT_CHECK([ovs-ofctl -O OpenFlow13 mod-table br0 2 name:])
AT_CHECK([ovs-ofctl -O OpenFlow15 dump-table-features br0 |grep '^  table'],
  [0], [dnl
  table 0 ("zero"):
  table 1 ("one"): ditto
  table 2: ditto
  table 3 ("three"): ditto
  tables 4...252: ditto
  table 253:
])

OVS_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([ofproto - table description (OpenFlow 1.4)])
OVS_VSWITCHD_START
(x=0
 while test $x -lt 254; do
   y=`expr $x + 1`
   echo "  table $x:
   eviction=off eviction_flags=OTHER|IMPORTANCE|LIFETIME
   vacancy=off"
   x=$y
 done) > expout
AT_CHECK([ovs-ofctl -O OpenFlow14 dump-table-desc br0 | sed '/^$/d
/^OFPST_TABLE_DESC/d'], [0], [expout])

# Change the configuration.
AT_CHECK([ovs-ofctl -O Openflow14 mod-table br0 0 evict])
# Check that the configuration was updated.
mv expout orig-expout
sed -e '2s/eviction=off/eviction=on/' <orig-expout > expout
AT_CHECK([ovs-ofctl -O OpenFlow14 dump-table-desc br0 | sed '/^$/d
/^OFPST_TABLE_DESC/d'], [0], [expout])

AT_CHECK([ovs-ofctl -O Openflow14 mod-table br0 0 vacancy:20,80])
# Check that the configuration was updated.
mv expout orig-expout
sed -e '3s/vacancy=off/vacancy=on vacancy_down=20% vacancy_up=80% vacancy=100%/' <orig-expout > expout
AT_CHECK([ovs-ofctl -O OpenFlow14 dump-table-desc br0 | sed '/^$/d
/^OFPST_TABLE_DESC/d'], [0], [expout])
OVS_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([ofproto - hard limits on flow table size (OpenFlow 1.0)])
OVS_VSWITCHD_START
# Configure a maximum of 4 flows.
AT_CHECK(
  [ovs-vsctl \
     -- --id=@t0 create Flow_Table flow-limit=4 \
     -- set bridge br0 flow_tables:0=@t0 \
   | uuidfilt],
  [0], [<0>
])
# Add 4 flows.
for in_port in 1 2 3 4; do
    ovs-ofctl add-flow br0 in_port=$in_port,actions=drop
done
AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort], [0], [dnl
 in_port=1 actions=drop
 in_port=2 actions=drop
 in_port=3 actions=drop
 in_port=4 actions=drop
NXST_FLOW reply:
])
# Adding another flow will be refused.
AT_CHECK([ovs-ofctl add-flow br0 in_port=5,actions=drop], [1], [], [stderr])
AT_CHECK([ofctl_strip < stderr], [0],
  [OFPT_ERROR: OFPFMFC_TABLE_FULL
OFPT_FLOW_MOD: ADD in_port=5 actions=drop
])
# Also a mod-flow that would add a flow will be refused.
AT_CHECK([ovs-ofctl mod-flows br0 in_port=5,actions=drop], [1], [], [stderr])
AT_CHECK([ofctl_strip < stderr], [0],
  [OFPT_ERROR: OFPFMFC_TABLE_FULL
OFPT_FLOW_MOD: MOD in_port=5 actions=drop
])
# Replacing or modifying an existing flow is allowed.
AT_CHECK([ovs-ofctl add-flow br0 in_port=4,actions=normal])
AT_CHECK([ovs-ofctl mod-flows br0 in_port=3,actions=output:1])
AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort], [0], [dnl
 in_port=1 actions=drop
 in_port=2 actions=drop
 in_port=3 actions=output:1
 in_port=4 actions=NORMAL
NXST_FLOW reply:
])
OVS_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([ofproto - hard limits on flow table size (OpenFlow 1.2)])
OVS_VSWITCHD_START
# Configure a maximum of 4 flows.
AT_CHECK(
  [ovs-vsctl \
     -- --id=@t0 create Flow_Table flow-limit=4 \
     -- set bridge br0 flow_tables:0=@t0 \
   | uuidfilt],
  [0], [<0>
])
# Add 4 flows.
for in_port in 1 2 3 4; do
    ovs-ofctl -O OpenFlow12 add-flow br0 in_port=$in_port,actions=drop
done
AT_CHECK([ovs-ofctl -O OpenFlow12 dump-flows br0 | ofctl_strip | sort], [0], [dnl
 in_port=1 actions=drop
 in_port=2 actions=drop
 in_port=3 actions=drop
 in_port=4 actions=drop
OFPST_FLOW reply (OF1.2):
])
# Adding another flow will be refused.
AT_CHECK([ovs-ofctl -O OpenFlow12 add-flow br0 in_port=5,actions=drop], [1], [], [stderr])
AT_CHECK([ofctl_strip < stderr], [0],
  [OFPT_ERROR (OF1.2): OFPFMFC_TABLE_FULL
OFPT_FLOW_MOD (OF1.2): ADD in_port=5 actions=drop
])
# Replacing or modifying an existing flow is allowed.
AT_CHECK([ovs-ofctl -O OpenFlow12 add-flow br0 in_port=4,actions=normal])
AT_CHECK([ovs-ofctl -O OpenFlow12 mod-flows br0 in_port=3,actions=output:1])
AT_CHECK([ovs-ofctl -O OpenFlow12 dump-flows br0 | ofctl_strip | sort], [0], [dnl
 in_port=1 actions=drop
 in_port=2 actions=drop
 in_port=3 actions=output:1
 in_port=4 actions=NORMAL
OFPST_FLOW reply (OF1.2):
])
OVS_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([ofproto - eviction upon table overflow (OpenFlow 1.0)])
OVS_VSWITCHD_START
# Configure a maximum of 4 flows.
AT_CHECK(
  [ovs-vsctl \
     -- --id=@t0 create Flow_Table flow-limit=4 overflow-policy=evict \
     -- set bridge br0 flow_tables:0=@t0 \
   | uuidfilt],
  [0], [<0>
])
# Add 4 flows.
for in_port in 4 3 2 1; do
    ovs-ofctl add-flow br0 idle_timeout=${in_port}0,in_port=$in_port,actions=drop
done
AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort], [0], [dnl
 idle_timeout=10, in_port=1 actions=drop
 idle_timeout=20, in_port=2 actions=drop
 idle_timeout=30, in_port=3 actions=drop
 idle_timeout=40, in_port=4 actions=drop
NXST_FLOW reply:
])
# Adding another flow will cause the one that expires soonest to be evicted.
AT_CHECK([ovs-ofctl add-flow br0 in_port=5,actions=drop])
AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort], [0], [dnl
 idle_timeout=20, in_port=2 actions=drop
 idle_timeout=30, in_port=3 actions=drop
 idle_timeout=40, in_port=4 actions=drop
 in_port=5 actions=drop
NXST_FLOW reply:
])
# A mod-flow that adds a flow also causes eviction, but replacing or
# modifying an existing flow doesn't.
AT_CHECK([ovs-ofctl mod-flows br0 in_port=6,actions=drop])
AT_CHECK([ovs-ofctl add-flow br0 in_port=4,actions=normal])
AT_CHECK([ovs-ofctl mod-flows br0 in_port=3,actions=output:1])
AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort], [0], [dnl
 idle_timeout=30, in_port=3 actions=output:1
 in_port=4 actions=NORMAL
 in_port=5 actions=drop
 in_port=6 actions=drop
NXST_FLOW reply:
])
# Flows with no timeouts at all cannot be evicted.
AT_CHECK([ovs-ofctl add-flow br0 in_port=7,actions=normal])
AT_CHECK([ovs-ofctl add-flow br0 in_port=8,actions=drop], [1], [], [stderr])
AT_CHECK([ofctl_strip < stderr], [0],
  [OFPT_ERROR: OFPFMFC_TABLE_FULL
OFPT_FLOW_MOD: ADD in_port=8 actions=drop
])
AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort], [0], [dnl
 in_port=4 actions=NORMAL
 in_port=5 actions=drop
 in_port=6 actions=drop
 in_port=7 actions=NORMAL
NXST_FLOW reply:
])
OVS_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([ofproto - eviction upon table overflow (OpenFlow 1.2)])
OVS_VSWITCHD_START
# Configure a maximum of 4 flows.
AT_CHECK(
  [ovs-vsctl \
     -- --id=@t0 create Flow_Table flow-limit=4 overflow-policy=evict \
     -- set bridge br0 flow_tables:0=@t0 \
   | uuidfilt],
  [0], [<0>
])
# Add 4 flows.
for in_port in 4 3 2 1; do
    ovs-ofctl -O OpenFlow12 add-flow br0 idle_timeout=${in_port}0,in_port=$in_port,actions=drop
done
AT_CHECK([ovs-ofctl -O OpenFlow12 dump-flows br0 | ofctl_strip | sort], [0], [dnl
 idle_timeout=10, in_port=1 actions=drop
 idle_timeout=20, in_port=2 actions=drop
 idle_timeout=30, in_port=3 actions=drop
 idle_timeout=40, in_port=4 actions=drop
OFPST_FLOW reply (OF1.2):
])
# Adding another flow will cause the one that expires soonest to be evicted.
AT_CHECK([ovs-ofctl -O OpenFlow12 add-flow br0 in_port=5,actions=drop])
AT_CHECK([ovs-ofctl -O OpenFlow12 dump-flows br0 | ofctl_strip | sort], [0], [dnl
 idle_timeout=20, in_port=2 actions=drop
 idle_timeout=30, in_port=3 actions=drop
 idle_timeout=40, in_port=4 actions=drop
 in_port=5 actions=drop
OFPST_FLOW reply (OF1.2):
])
# In OpenFlow 1.2 a mod-flow does not ever add a flow and thus
# has no effect on eviction
AT_CHECK([ovs-ofctl -O OpenFlow12 mod-flows br0 in_port=6,actions=drop])
AT_CHECK([ovs-ofctl -O OpenFlow12 add-flow br0 in_port=4,actions=normal])
AT_CHECK([ovs-ofctl -O OpenFlow12 mod-flows br0 in_port=3,actions=output:1])
AT_CHECK([ovs-ofctl -O OpenFlow12 dump-flows br0 | ofctl_strip | sort], [0], [dnl
 idle_timeout=20, in_port=2 actions=drop
 idle_timeout=30, in_port=3 actions=output:1
 in_port=4 actions=NORMAL
 in_port=5 actions=drop
OFPST_FLOW reply (OF1.2):
])
# Flows with no timeouts at all cannot be evicted.
AT_CHECK([ovs-ofctl -O OpenFlow12 add-flow br0 in_port=6,actions=drop])
AT_CHECK([ovs-ofctl -O OpenFlow12 add-flow br0 in_port=7,actions=normal])
AT_CHECK([ovs-ofctl -O OpenFlow12 add-flow br0 in_port=8,actions=drop], [1], [], [stderr])
AT_CHECK([ofctl_strip < stderr], [0],
  [OFPT_ERROR (OF1.2): OFPFMFC_TABLE_FULL
OFPT_FLOW_MOD (OF1.2): ADD in_port=8 actions=drop
])
AT_CHECK([ovs-ofctl -O OpenFlow12 dump-flows br0 | ofctl_strip | sort], [0], [dnl
 in_port=4 actions=NORMAL
 in_port=5 actions=drop
 in_port=6 actions=drop
 in_port=7 actions=NORMAL
OFPST_FLOW reply (OF1.2):
])
OVS_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([ofproto - eviction using importance upon table overflow (OpenFlow 1.4)])
OVS_VSWITCHD_START
# Configure a maximum of 4 flows.
AT_CHECK(
  [ovs-vsctl \
     -- --id=@t0 create Flow_Table name=evict flow-limit=4 \
     -- set bridge br0 flow_tables:0=@t0 \
   | uuidfilt],
  [0], [<0>
])
# Use mod-table to turn on eviction just to demonstrate that it works.
AT_CHECK([ovs-ofctl -O OpenFlow14 mod-table br0 0 evict])
# Add 4 flows.
for in_port in 4 3 2 1; do
    ovs-ofctl -O Openflow14 add-flow br0 importance=$((in_port + 30)),priority=$((in_port + 5)),hard_timeout=$((in_port + 500)),actions=drop
done
AT_CHECK([ovs-ofctl -O Openflow14 dump-flows br0 | ofctl_strip | sort], [0], [dnl
 hard_timeout=501, importance=31, priority=6 actions=drop
 hard_timeout=502, importance=32, priority=7 actions=drop
 hard_timeout=503, importance=33, priority=8 actions=drop
 hard_timeout=504, importance=34, priority=9 actions=drop
OFPST_FLOW reply (OF1.4):
])
# Adding another flow will cause the one with lowest importance to be evicted.
AT_CHECK([ovs-ofctl -O Openflow14 add-flow br0 hard_timeout=505,importance=35,priority=10,in_port=2,actions=drop])
AT_CHECK([ovs-ofctl -O Openflow14 dump-flows br0 | ofctl_strip | sort], [0], [dnl
 hard_timeout=502, importance=32, priority=7 actions=drop
 hard_timeout=503, importance=33, priority=8 actions=drop
 hard_timeout=504, importance=34, priority=9 actions=drop
 hard_timeout=505, importance=35, priority=10,in_port=2 actions=drop
OFPST_FLOW reply (OF1.4):
])
# Disable the Eviction configuration.
AT_CHECK([ovs-ofctl -O OpenFlow14 mod-table br0 0 noevict])
# Adding another flow will cause the system to give error for FULL TABLE.
AT_CHECK([ovs-ofctl -O Openflow14 add-flow br0 hard_timeout=506,importance=36,priority=11,actions=drop],[1], [], [stderr])
AT_CHECK([ofctl_strip < stderr], [0],
 [OFPT_ERROR (OF1.4): OFPFMFC_TABLE_FULL
OFPT_FLOW_MOD (OF1.4): ADD priority=11 hard:506 importance:36 actions=drop
])
#Dump flows. It should show only the old values
AT_CHECK([ovs-ofctl -O Openflow14 dump-flows br0 | ofctl_strip | sort], [0], [dnl
 hard_timeout=502, importance=32, priority=7 actions=drop
 hard_timeout=503, importance=33, priority=8 actions=drop
 hard_timeout=504, importance=34, priority=9 actions=drop
 hard_timeout=505, importance=35, priority=10,in_port=2 actions=drop
OFPST_FLOW reply (OF1.4):
])
# mod-flow that would modify a flow will be done successfully.
AT_CHECK([ovs-ofctl -O Openflow14 mod-flows br0 in_port=2,actions=NORMAL])
AT_CHECK([ovs-ofctl -O Openflow14 dump-flows br0 | ofctl_strip | sort], [0], [dnl
 hard_timeout=502, importance=32, priority=7 actions=drop
 hard_timeout=503, importance=33, priority=8 actions=drop
 hard_timeout=504, importance=34, priority=9 actions=drop
 hard_timeout=505, importance=35, priority=10,in_port=2 actions=NORMAL
OFPST_FLOW reply (OF1.4):
])
# Also a mod-flow that would add a flow will be refused.
AT_CHECK([ovs-ofctl mod-flows br0 in_port=5,actions=drop], [1], [], [stderr])
AT_CHECK([ofctl_strip < stderr], [0],
  [OFPT_ERROR: OFPFMFC_TABLE_FULL
OFPT_FLOW_MOD: MOD in_port=5 actions=drop
])
OVS_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([ofproto - eviction upon table overflow, with fairness (OpenFlow 1.0)])
OVS_VSWITCHD_START
# Configure a maximum of 4 flows.
AT_CHECK(
  [ovs-vsctl \
     -- --id=@t0 create Flow_Table name=evict flow-limit=4 \
                                   overflow-policy=evict \
                                   groups='"NXM_OF_IN_PORT[[]]"' \
     -- set bridge br0 flow_tables:0=@t0 \
   | uuidfilt],
  [0], [<0>
])
# Add 4 flows.
ovs-ofctl add-flows br0 - <<EOF
idle_timeout=10 in_port=2 dl_src=00:44:55:66:77:88 actions=drop
idle_timeout=20 in_port=1 dl_src=00:11:22:33:44:55 actions=drop
idle_timeout=30 in_port=1 dl_src=00:22:33:44:55:66 actions=drop
idle_timeout=40 in_port=1 dl_src=00:33:44:55:66:77 actions=drop
EOF
AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort], [0], [dnl
 idle_timeout=10, in_port=2,dl_src=00:44:55:66:77:88 actions=drop
 idle_timeout=20, in_port=1,dl_src=00:11:22:33:44:55 actions=drop
 idle_timeout=30, in_port=1,dl_src=00:22:33:44:55:66 actions=drop
 idle_timeout=40, in_port=1,dl_src=00:33:44:55:66:77 actions=drop
NXST_FLOW reply:
])
# Adding another flow will cause the one that expires soonest within
# the largest group (those with in_port=1) to be evicted.  In this
# case this is not the same as the one that expires soonest overall
# (which is what makes the test interesting):
AT_CHECK([ovs-ofctl add-flow br0 in_port=2,dl_src=00:55:66:77:88:99,actions=drop])
AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort], [0], [dnl
 idle_timeout=10, in_port=2,dl_src=00:44:55:66:77:88 actions=drop
 idle_timeout=30, in_port=1,dl_src=00:22:33:44:55:66 actions=drop
 idle_timeout=40, in_port=1,dl_src=00:33:44:55:66:77 actions=drop
 in_port=2,dl_src=00:55:66:77:88:99 actions=drop
NXST_FLOW reply:
])
# Enlarge the flow limit, change the eviction policy back to strictly
# based on expiration, and and add some flows.
AT_CHECK([ovs-vsctl set Flow_Table evict groups='[[]]' flow-limit=7])
ovs-ofctl add-flows br0 - <<EOF
idle_timeout=50 in_port=2 dl_src=00:66:77:88:99:aa actions=drop
idle_timeout=60 in_port=2 dl_src=00:77:88:99:aa:bb actions=drop
idle_timeout=70 in_port=2 dl_src=00:88:99:aa:bb:cc actions=drop
EOF
AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort], [0], [dnl
 idle_timeout=10, in_port=2,dl_src=00:44:55:66:77:88 actions=drop
 idle_timeout=30, in_port=1,dl_src=00:22:33:44:55:66 actions=drop
 idle_timeout=40, in_port=1,dl_src=00:33:44:55:66:77 actions=drop
 idle_timeout=50, in_port=2,dl_src=00:66:77:88:99:aa actions=drop
 idle_timeout=60, in_port=2,dl_src=00:77:88:99:aa:bb actions=drop
 idle_timeout=70, in_port=2,dl_src=00:88:99:aa:bb:cc actions=drop
 in_port=2,dl_src=00:55:66:77:88:99 actions=drop
NXST_FLOW reply:
])
# Adding another flow will cause the one that expires soonest overall
# to be evicted.
AT_CHECK([ovs-ofctl add-flow br0 'idle_timeout=80 in_port=2 dl_src=00:99:aa:bb:cc:dd actions=drop'])
AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort], [0], [dnl
 idle_timeout=30, in_port=1,dl_src=00:22:33:44:55:66 actions=drop
 idle_timeout=40, in_port=1,dl_src=00:33:44:55:66:77 actions=drop
 idle_timeout=50, in_port=2,dl_src=00:66:77:88:99:aa actions=drop
 idle_timeout=60, in_port=2,dl_src=00:77:88:99:aa:bb actions=drop
 idle_timeout=70, in_port=2,dl_src=00:88:99:aa:bb:cc actions=drop
 idle_timeout=80, in_port=2,dl_src=00:99:aa:bb:cc:dd actions=drop
 in_port=2,dl_src=00:55:66:77:88:99 actions=drop
NXST_FLOW reply:
])
# Reducing the flow limit also causes the flows that expire soonest
# overall to be evicted.
AT_CHECK([ovs-vsctl set Flow_Table evict flow-limit=4])
AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort], [0], [dnl
 idle_timeout=60, in_port=2,dl_src=00:77:88:99:aa:bb actions=drop
 idle_timeout=70, in_port=2,dl_src=00:88:99:aa:bb:cc actions=drop
 idle_timeout=80, in_port=2,dl_src=00:99:aa:bb:cc:dd actions=drop
 in_port=2,dl_src=00:55:66:77:88:99 actions=drop
NXST_FLOW reply:
])
OVS_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([ofproto - eviction upon table overflow, with fairness (OpenFlow 1.2)])
OVS_VSWITCHD_START
# Configure a maximum of 4 flows.
AT_CHECK(
  [ovs-vsctl \
     -- --id=@t0 create Flow_Table name=evict flow-limit=4 \
                                   overflow-policy=evict \
                                   groups='"NXM_OF_IN_PORT[[]]"' \
     -- set bridge br0 flow_tables:0=@t0 \
   | uuidfilt],
  [0], [<0>
])
# Add 4 flows.
ovs-ofctl -O OpenFlow12 add-flows br0 - <<EOF
idle_timeout=10 in_port=2 dl_src=00:44:55:66:77:88 actions=drop
idle_timeout=20 in_port=1 dl_src=00:11:22:33:44:55 actions=drop
idle_timeout=30 in_port=1 dl_src=00:22:33:44:55:66 actions=drop
idle_timeout=40 in_port=1 dl_src=00:33:44:55:66:77 actions=drop
EOF
AT_CHECK([ovs-ofctl -O OpenFlow12 dump-flows br0 | ofctl_strip | sort], [0], [dnl
 idle_timeout=10, in_port=2,dl_src=00:44:55:66:77:88 actions=drop
 idle_timeout=20, in_port=1,dl_src=00:11:22:33:44:55 actions=drop
 idle_timeout=30, in_port=1,dl_src=00:22:33:44:55:66 actions=drop
 idle_timeout=40, in_port=1,dl_src=00:33:44:55:66:77 actions=drop
OFPST_FLOW reply (OF1.2):
])
# Adding another flow will cause the one that expires soonest within
# the largest group (those with in_port=1) to be evicted.  In this
# case this is not the same as the one that expires soonest overall
# (which is what makes the test interesting):
AT_CHECK([ovs-ofctl -O OpenFlow12 add-flow br0 in_port=2,dl_src=00:55:66:77:88:99,actions=drop])
AT_CHECK([ovs-ofctl -O OpenFlow12 dump-flows br0 | ofctl_strip | sort], [0], [dnl
 idle_timeout=10, in_port=2,dl_src=00:44:55:66:77:88 actions=drop
 idle_timeout=30, in_port=1,dl_src=00:22:33:44:55:66 actions=drop
 idle_timeout=40, in_port=1,dl_src=00:33:44:55:66:77 actions=drop
 in_port=2,dl_src=00:55:66:77:88:99 actions=drop
OFPST_FLOW reply (OF1.2):
])
# Enlarge the flow limit, change the eviction policy back to strictly
# based on expiration, and and add some flows.
AT_CHECK([ovs-vsctl set Flow_Table evict groups='[[]]' flow-limit=7])
ovs-ofctl -O OpenFlow12 add-flows br0 - <<EOF
idle_timeout=50 in_port=2 dl_src=00:66:77:88:99:aa actions=drop
idle_timeout=60 in_port=2 dl_src=00:77:88:99:aa:bb actions=drop
idle_timeout=70 in_port=2 dl_src=00:88:99:aa:bb:cc actions=drop
EOF
AT_CHECK([ovs-ofctl -O OpenFlow12 dump-flows br0 | ofctl_strip | sort], [0], [dnl
 idle_timeout=10, in_port=2,dl_src=00:44:55:66:77:88 actions=drop
 idle_timeout=30, in_port=1,dl_src=00:22:33:44:55:66 actions=drop
 idle_timeout=40, in_port=1,dl_src=00:33:44:55:66:77 actions=drop
 idle_timeout=50, in_port=2,dl_src=00:66:77:88:99:aa actions=drop
 idle_timeout=60, in_port=2,dl_src=00:77:88:99:aa:bb actions=drop
 idle_timeout=70, in_port=2,dl_src=00:88:99:aa:bb:cc actions=drop
 in_port=2,dl_src=00:55:66:77:88:99 actions=drop
OFPST_FLOW reply (OF1.2):
])
# Adding another flow will cause the one that expires soonest overall
# to be evicted.
AT_CHECK([ovs-ofctl -O OpenFlow12 add-flow br0 'idle_timeout=80 in_port=2 dl_src=00:99:aa:bb:cc:dd actions=drop'])
AT_CHECK([ovs-ofctl -O OpenFlow12 dump-flows br0 | ofctl_strip | sort], [0], [dnl
 idle_timeout=30, in_port=1,dl_src=00:22:33:44:55:66 actions=drop
 idle_timeout=40, in_port=1,dl_src=00:33:44:55:66:77 actions=drop
 idle_timeout=50, in_port=2,dl_src=00:66:77:88:99:aa actions=drop
 idle_timeout=60, in_port=2,dl_src=00:77:88:99:aa:bb actions=drop
 idle_timeout=70, in_port=2,dl_src=00:88:99:aa:bb:cc actions=drop
 idle_timeout=80, in_port=2,dl_src=00:99:aa:bb:cc:dd actions=drop
 in_port=2,dl_src=00:55:66:77:88:99 actions=drop
OFPST_FLOW reply (OF1.2):
])
# Reducing the flow limit also causes the flows that expire soonest
# overall to be evicted.
AT_CHECK([ovs-vsctl set Flow_Table evict flow-limit=4])
AT_CHECK([ovs-ofctl -O OpenFlow12 dump-flows br0 | ofctl_strip | sort], [0], [dnl
 idle_timeout=60, in_port=2,dl_src=00:77:88:99:aa:bb actions=drop
 idle_timeout=70, in_port=2,dl_src=00:88:99:aa:bb:cc actions=drop
 idle_timeout=80, in_port=2,dl_src=00:99:aa:bb:cc:dd actions=drop
 in_port=2,dl_src=00:55:66:77:88:99 actions=drop
OFPST_FLOW reply (OF1.2):
])
OVS_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([ofproto - eviction upon table overflow, with modified hard timeout])
OVS_VSWITCHD_START
# Configure a maximum of 4 flows.
AT_CHECK(
  [ovs-vsctl \
     -- --id=@t0 create Flow_Table flow-limit=4 overflow-policy=evict \
     -- set bridge br0 flow_tables:0=@t0 \
   | uuidfilt],
  [0], [<0>
])
ovs-appctl time/stop
# Add 4 flows.
for in_port in 4 3 2 1; do
    ovs-ofctl add-flow br0 hard_timeout=$((10 + in_port * 3)),in_port=$in_port,actions=drop
done
AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort], [0], [dnl
 hard_timeout=13, in_port=1 actions=drop
 hard_timeout=16, in_port=2 actions=drop
 hard_timeout=19, in_port=3 actions=drop
 hard_timeout=22, in_port=4 actions=drop
NXST_FLOW reply:
])
# Sleep and modify the one that expires soonest
ovs-appctl time/warp 5000
AT_CHECK([ovs-ofctl mod-flows br0 in_port=1,actions=drop])
# At this point the table would looks like:
#  in_port   seconds to expire
#     1            13
#     2            11
#     3            14
#     4            17
ovs-appctl time/warp 2000
# Adding another flow will cause the one that expires soonest to be evicted.
AT_CHECK([ovs-ofctl add-flow br0 in_port=5,actions=drop])
AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort], [0], [dnl
 hard_timeout=13, in_port=1 actions=drop
 hard_timeout=19, in_port=3 actions=drop
 hard_timeout=22, in_port=4 actions=drop
 in_port=5 actions=drop
NXST_FLOW reply:
])
OVS_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([ofproto - eviction upon table overflow, with modified idle timeout])
OVS_VSWITCHD_START([add-port br0 p1 -- set interface p1 type=dummy ofport_request=1])
# Configure a maximum of 4 flows.
AT_CHECK(
  [ovs-vsctl \
     -- --id=@t0 create Flow_Table flow-limit=4 overflow-policy=evict \
     -- set bridge br0 flow_tables:0=@t0 \
   | uuidfilt],
  [0], [<0>
])
# Add 4 flows.
for in_port in 4 3 2 1; do
    ovs-ofctl add-flow br0 idle_timeout=$((10 + in_port * 3)),in_port=$in_port,actions=drop
done
ovs-appctl time/stop
AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort], [0], [dnl
 idle_timeout=13, in_port=1 actions=drop
 idle_timeout=16, in_port=2 actions=drop
 idle_timeout=19, in_port=3 actions=drop
 idle_timeout=22, in_port=4 actions=drop
NXST_FLOW reply:
])
# Sleep and receive on the flow that expires soonest
ovs-appctl time/warp 5000
AT_CHECK([ovs-appctl netdev-dummy/receive p1 'in_port(1)'])
# At this point the table would looks like:
#  in_port   seconds to expire
#     1            13
#     2            11
#     3            14
#     4            17
ovs-appctl time/warp 2000
# Adding another flow will cause the one that expires soonest to be evicted.
AT_CHECK([ovs-ofctl add-flow br0 in_port=5,actions=drop])
AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort], [0], [dnl
 idle_timeout=19, in_port=3 actions=drop
 idle_timeout=22, in_port=4 actions=drop
 in_port=5 actions=drop
 n_packets=1, n_bytes=14, idle_timeout=13, in_port=1 actions=drop
NXST_FLOW reply:
])
OVS_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([ofproto - asynchronous message control (OpenFlow 1.0)])
OVS_VSWITCHD_START([set bridge br0 other_config:hwaddr=00:01:02:03:04:05])
AT_CHECK([ovs-ofctl -P standard monitor br0 --detach --no-chdir --pidfile])
check_async () {
    printf '\n\n--- check_async %d ---\n\n\n' $1
    shift

    ovs-appctl -t ovs-ofctl ofctl/barrier
    ovs-appctl -t ovs-ofctl ofctl/set-output-file monitor.log
    : > expout

    # OFPT_PACKET_IN, OFPR_ACTION (controller_id=0)
    ovs-ofctl -v packet-out br0 controller controller '0001020304050010203040501234'
    if test X"$1" = X"OFPR_ACTION"; then shift;
        echo >>expout "OFPT_PACKET_IN: total_len=14 in_port=CONTROLLER (via action) data_len=14 (unbuffered)
vlan_tci=0x0000,dl_src=00:10:20:30:40:50,dl_dst=00:01:02:03:04:05,dl_type=0x1234"
    fi

    # OFPT_PACKET_IN, OFPR_NO_MATCH (controller_id=123)
    ovs-ofctl -v packet-out br0 controller 'controller(reason=no_match,id=123)' '0001020304050010203040501234'
    if test X"$1" = X"OFPR_NO_MATCH"; then shift;
        echo >>expout "OFPT_PACKET_IN: total_len=14 in_port=CONTROLLER (via no_match) data_len=14 (unbuffered)
vlan_tci=0x0000,dl_src=00:10:20:30:40:50,dl_dst=00:01:02:03:04:05,dl_type=0x1234"
    fi

    # OFPT_PACKET_IN, OFPR_INVALID_TTL (controller_id=0)
    ovs-ofctl packet-out br0 "in_port=controller packet=002583dfb4000026b98cb0f908004500003eb7e200000011339bac11370dac100002d7730035002b8f6d86fb0100000100000000000006626c702d7873066e696369726103636f6d00000f00 actions=dec_ttl"
    if test X"$1" = X"OFPR_INVALID_TTL"; then shift;
        echo >>expout "OFPT_PACKET_IN: total_len=76 in_port=CONTROLLER (via invalid_ttl) data_len=76 (unbuffered)
udp,vlan_tci=0x0000,dl_src=00:26:b9:8c:b0:f9,dl_dst=00:25:83:df:b4:00,nw_src=172.17.55.13,nw_dst=172.16.0.2,nw_tos=0,nw_ecn=0,nw_ttl=0,nw_frag=no,tp_src=55155,tp_dst=53 udp_csum:8f6d"
    fi

    # OFPT_PORT_STATUS, OFPPR_ADD
    ovs-vsctl add-port br0 test -- set Interface test type=dummy ofport_request=1
    if test X"$1" = X"OFPPR_ADD"; then shift;
        echo >>expout "OFPT_PORT_STATUS: ADD: 1(test): addr:aa:55:aa:55:00:0x
     config:     0
     state:      0
     speed: 0 Mbps now, 0 Mbps max"
    fi

    # OFPT_PORT_STATUS, OFPPR_DELETE
    ovs-vsctl del-port br0 test
    if test X"$1" = X"OFPPR_DELETE"; then shift;
        echo >>expout "OFPT_PORT_STATUS: DEL: 1(test): addr:aa:55:aa:55:00:0x
     config:     0
     state:      0
     speed: 0 Mbps now, 0 Mbps max"
    fi

    # OFPT_FLOW_REMOVED, OFPRR_DELETE
    ovs-ofctl add-flow br0 send_flow_rem,actions=drop
    ovs-ofctl --strict del-flows br0 ''
    if test X"$1" = X"OFPRR_DELETE"; then shift;
        echo >>expout "OFPT_FLOW_REMOVED:  reason=delete"
    fi
    AT_FAIL_IF([test X"$1" != X])

    OVS_WAIT_UNTIL([test `wc -l < "monitor.log"` -ge `wc -l < "expout"`])

    AT_CHECK(
      [[sed '
s/ (xid=0x[0-9a-fA-F]*)//
s/ *duration.*//
s/00:0.$/00:0x/' < monitor.log]],
      [0], [expout])
}

# It's a service connection so initially there should be no async messages.
check_async 1

# Set miss_send_len to 128, turning on packet-ins for our service connection.
ovs-appctl -t ovs-ofctl ofctl/send 0109000c0123456700000080
check_async 2 OFPR_ACTION OFPPR_ADD OFPPR_DELETE OFPRR_DELETE

# Set miss_send_len to 128 and enable invalid_ttl.
ovs-appctl -t ovs-ofctl ofctl/send 0109000c0123456700040080
check_async 3 OFPR_ACTION OFPR_INVALID_TTL OFPPR_ADD OFPPR_DELETE OFPRR_DELETE

# Become secondary, which should disable everything except port status.
ovs-appctl -t ovs-ofctl ofctl/send 0104001400000002000023200000000a00000002
check_async 4 OFPPR_ADD OFPPR_DELETE

# Use NXT_SET_ASYNC_CONFIG to enable a patchwork of asynchronous messages.
ovs-appctl -t ovs-ofctl ofctl/send 01040028000000020000232000000013000000020000000500000005000000020000000200000005
check_async 5 OFPR_INVALID_TTL OFPPR_DELETE OFPRR_DELETE

# Set controller ID 123.
ovs-appctl -t ovs-ofctl ofctl/send 01040018000000030000232000000014000000000000007b
check_async 6 OFPR_NO_MATCH OFPPR_DELETE OFPRR_DELETE

# Restore controller ID 0.
ovs-appctl -t ovs-ofctl ofctl/send 010400180000000300002320000000140000000000000000

# Become primary.
ovs-appctl -t ovs-ofctl ofctl/send 0104001400000002000023200000000a00000001
check_async 7 OFPR_ACTION OFPPR_ADD

OVS_APP_EXIT_AND_WAIT([ovs-ofctl])
OVS_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([ofproto - asynchronous message control (OpenFlow 1.2)])
OVS_VSWITCHD_START
AT_CHECK([ovs-ofctl -O OpenFlow12 -P standard monitor br0 --detach --no-chdir --pidfile])
check_async () {
    printf '\n\n--- check_async %d ---\n\n\n' $1
    INDEX=$1
    shift

    ovs-appctl -t ovs-ofctl ofctl/barrier
    ovs-appctl -t ovs-ofctl ofctl/set-output-file monitor.log
    : > expout

    # OFPT_PACKET_IN, OFPR_ACTION (controller_id=0)
    ovs-ofctl -O OpenFlow12 -v packet-out br0 none controller '0001020304050010203040501234'
    if test X"$1" = X"OFPR_ACTION"; then shift;
        echo >>expout "OFPT_PACKET_IN (OF1.2): total_len=14 in_port=ANY (via action) data_len=14 (unbuffered)
vlan_tci=0x0000,dl_src=00:10:20:30:40:50,dl_dst=00:01:02:03:04:05,dl_type=0x1234"
    fi

    # OFPT_PACKET_IN, OFPR_NO_MATCH (controller_id=123)
    ovs-ofctl -O OpenFlow12 -v packet-out br0 none 'controller(reason=no_match,id=123)' '0001020304050010203040501234'
    if test X"$1" = X"OFPR_NO_MATCH"; then shift;
        echo >>expout "OFPT_PACKET_IN (OF1.2): total_len=14 in_port=ANY (via no_match) data_len=14 (unbuffered)
vlan_tci=0x0000,dl_src=00:10:20:30:40:50,dl_dst=00:01:02:03:04:05,dl_type=0x1234"
    fi

    # OFPT_PACKET_IN, OFPR_INVALID_TTL (controller_id=0)
    ovs-ofctl -O OpenFlow12 packet-out br0 none dec_ttl '002583dfb4000026b98cb0f908004500003eb7e200000011339bac11370dac100002d7730035002b8f6d86fb0100000100000000000006626c702d7873066e696369726103636f6d00000f00'
    if test X"$1" = X"OFPR_INVALID_TTL"; then shift;
        echo >>expout "OFPT_PACKET_IN (OF1.2): total_len=76 in_port=ANY (via invalid_ttl) data_len=76 (unbuffered)
udp,vlan_tci=0x0000,dl_src=00:26:b9:8c:b0:f9,dl_dst=00:25:83:df:b4:00,nw_src=172.17.55.13,nw_dst=172.16.0.2,nw_tos=0,nw_ecn=0,nw_ttl=0,nw_frag=no,tp_src=55155,tp_dst=53 udp_csum:8f6d"
    fi

    # OFPT_PORT_STATUS, OFPPR_ADD
    ovs-vsctl add-port br0 test -- set Interface test type=dummy
    if test X"$1" = X"OFPPR_ADD"; then shift;
        echo >>expout "OFPT_PORT_STATUS (OF1.2): ADD: ${INDEX}(test): addr:aa:55:aa:55:00:0x
     config:     0
     state:      0
     speed: 0 Mbps now, 0 Mbps max
OFPT_PORT_STATUS (OF1.2): MOD: ${INDEX}(test): addr:aa:55:aa:55:00:0x
     config:     0
     state:      LIVE
     speed: 0 Mbps now, 0 Mbps max"
    fi

    # OFPT_PORT_STATUS, OFPPR_DELETE
    ovs-vsctl del-port br0 test
    if test X"$1" = X"OFPPR_DELETE"; then shift;
        echo >>expout "OFPT_PORT_STATUS (OF1.2): DEL: ${INDEX}(test): addr:aa:55:aa:55:00:0x
     config:     0
     state:      LIVE
     speed: 0 Mbps now, 0 Mbps max"
    fi

    # OFPT_FLOW_REMOVED, OFPRR_DELETE
    ovs-ofctl -O OpenFlow12 add-flow br0 send_flow_rem,actions=drop
    ovs-ofctl -O OpenFlow12 --strict del-flows br0 ''
    if test X"$1" = X"OFPRR_DELETE"; then shift;
        echo >>expout "OFPT_FLOW_REMOVED (OF1.2):  reason=delete table_id=0"
    fi
    AT_FAIL_IF([test X"$1" != X])

    OVS_WAIT_UNTIL([test `wc -l < "monitor.log"` -ge `wc -l < "expout"`])

    AT_CHECK(
      [[sed '
s/ (xid=0x[0-9a-fA-F]*)//
s/ *duration.*//
s/00:0.$/00:0x/' < monitor.log]],
      [0], [expout])
}

# It's a service connection so initially there should be no async messages.
check_async 1

# Set miss_send_len to 128, turning on packet-ins for our service connection.
ovs-appctl -t ovs-ofctl ofctl/send 0309000c0123456700000080
check_async 2 OFPR_ACTION OFPPR_ADD OFPPR_DELETE OFPRR_DELETE

# Set miss_send_len to 128 and enable invalid_ttl.
ovs-appctl -t ovs-ofctl ofctl/send 0309000c0123456700040080
check_async 3 OFPR_ACTION OFPR_INVALID_TTL OFPPR_ADD OFPPR_DELETE OFPRR_DELETE

# Become secondary (OF 1.2), which should disable everything except port status.
ovs-appctl -t ovs-ofctl ofctl/send 031800180000000200000003000000000000000000000001
check_async 4 OFPPR_ADD OFPPR_DELETE

# Use NXT_SET_ASYNC_CONFIG to enable a patchwork of asynchronous messages.
ovs-appctl -t ovs-ofctl ofctl/send 03040028000000020000232000000013000000020000000500000005000000020000000200000005
check_async 5 OFPR_INVALID_TTL OFPPR_DELETE OFPRR_DELETE

# Set controller ID 123.
ovs-appctl -t ovs-ofctl ofctl/send 03040018000000030000232000000014000000000000007b
check_async 6 OFPR_NO_MATCH OFPPR_DELETE OFPRR_DELETE

# Restore controller ID 0.
ovs-appctl -t ovs-ofctl ofctl/send 030400180000000300002320000000140000000000000000

# Become primary (OF 1.2).
ovs-appctl -t ovs-ofctl ofctl/send 031800180000000400000002000000000000000000000002
check_async 7 OFPR_ACTION OFPPR_ADD

OVS_APP_EXIT_AND_WAIT([ovs-ofctl])
OVS_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([ofproto - asynchronous message control (OpenFlow 1.3)])
OVS_VSWITCHD_START([dnl
    add-port br0 p1 -- set Interface p1 type=dummy ofport_request=10
])
AT_CHECK([ovs-ofctl -O OpenFlow13 -P standard monitor br0 --detach --no-chdir --pidfile])
check_async () {
    printf '\n\n--- check_async %d ---\n\n\n' $1
    INDEX=$1
    shift

    ovs-appctl -t ovs-ofctl ofctl/barrier
    ovs-appctl -t ovs-ofctl ofctl/set-output-file monitor.log
    : > expout

    # OFPT_PACKET_IN, OFPR_ACTION (controller_id=0)
    # OFPR_ACTION_SET is treated as OFPR_ACTION in OpenFlow 1.3
    ovs-ofctl -O OpenFlow13 -v packet-out br0 none controller '0001020304050010203040501234'
    ovs-ofctl -O OpenFlow13 add-flow br0 'in_port=10 actions=write_actions(output(CONTROLLER))'
    ovs-appctl netdev-dummy/receive p1 'in_port(10),eth(src=00:10:20:30:40:50,dst=00:01:02:03:04:05),eth_type(0x1234)'
    if test X"$1" = X"OFPR_ACTION"; then shift;
        echo >>expout "OFPT_PACKET_IN (OF1.3): total_len=14 in_port=ANY (via action) data_len=14 (unbuffered)
vlan_tci=0x0000,dl_src=00:10:20:30:40:50,dl_dst=00:01:02:03:04:05,dl_type=0x1234"
        echo >>expout "OFPT_PACKET_IN (OF1.3): cookie=0x0 total_len=14 in_port=10 (via action) data_len=14 (unbuffered)
vlan_tci=0x0000,dl_src=00:10:20:30:40:50,dl_dst=00:01:02:03:04:05,dl_type=0x1234"
    fi

    # OFPT_PACKET_IN, OFPR_NO_MATCH (controller_id=123)
    ovs-ofctl -O OpenFlow13 -v packet-out br0 none 'controller(reason=no_match,id=123)' '0001020304050010203040501234'
    if test X"$1" = X"OFPR_NO_MATCH"; then shift;
        echo >>expout "OFPT_PACKET_IN (OF1.3): total_len=14 in_port=ANY (via no_match) data_len=14 (unbuffered)
vlan_tci=0x0000,dl_src=00:10:20:30:40:50,dl_dst=00:01:02:03:04:05,dl_type=0x1234"
    fi

    # OFPT_PACKET_IN, OFPR_INVALID_TTL (controller_id=0)
    ovs-ofctl -O OpenFlow13 packet-out br0 none dec_ttl '002583dfb4000026b98cb0f908004500003eb7e200000011339bac11370dac100002d7730035002b8f6d86fb0100000100000000000006626c702d7873066e696369726103636f6d00000f00'
    if test X"$1" = X"OFPR_INVALID_TTL"; then shift;
        echo >>expout "OFPT_PACKET_IN (OF1.3): total_len=76 in_port=ANY (via invalid_ttl) data_len=76 (unbuffered)
udp,vlan_tci=0x0000,dl_src=00:26:b9:8c:b0:f9,dl_dst=00:25:83:df:b4:00,nw_src=172.17.55.13,nw_dst=172.16.0.2,nw_tos=0,nw_ecn=0,nw_ttl=0,nw_frag=no,tp_src=55155,tp_dst=53 udp_csum:8f6d"
    fi

    # OFPT_PORT_STATUS, OFPPR_ADD
    ovs-vsctl add-port br0 test -- set Interface test type=dummy
    if test X"$1" = X"OFPPR_ADD"; then shift;
        echo >>expout "OFPT_PORT_STATUS (OF1.3): ADD: ${INDEX}(test): addr:aa:55:aa:55:00:0x
     config:     0
     state:      0
     speed: 0 Mbps now, 0 Mbps max
OFPT_PORT_STATUS (OF1.3): MOD: ${INDEX}(test): addr:aa:55:aa:55:00:0x
     config:     0
     state:      LIVE
     speed: 0 Mbps now, 0 Mbps max"
    fi

    # OFPT_PORT_STATUS, OFPPR_DELETE
    ovs-vsctl del-port br0 test
    if test X"$1" = X"OFPPR_DELETE"; then shift;
        echo >>expout "OFPT_PORT_STATUS (OF1.3): DEL: ${INDEX}(test): addr:aa:55:aa:55:00:0x
     config:     0
     state:      LIVE
     speed: 0 Mbps now, 0 Mbps max"
    fi

    # OFPT_FLOW_REMOVED, OFPRR_DELETE
    ovs-ofctl -O OpenFlow13 add-flow br0 send_flow_rem,actions=drop
    ovs-ofctl -O OpenFlow13 --strict del-flows br0 ''
    if test X"$1" = X"OFPRR_DELETE"; then shift;
        echo >>expout "OFPT_FLOW_REMOVED (OF1.3):  reason=delete table_id=0"
    fi

    # OFPT_FLOW_REMOVED, OFPRR_GROUP_DELETE
    ovs-ofctl -O OpenFlow13 add-group br0 group_id=1234,type=all,bucket=output:10
    ovs-ofctl -O OpenFlow13 add-flow br0 send_flow_rem,actions=group:1234
    ovs-ofctl -O OpenFlow13 --strict del-groups br0 group_id=1234
    if test X"$1" = X"OFPRR_GROUP_DELETE"; then shift;
        echo >>expout "OFPT_FLOW_REMOVED (OF1.3):  reason=group_delete table_id=0"
    fi

    AT_FAIL_IF([test X"$1" != X])

    OVS_WAIT_UNTIL([test `wc -l < "monitor.log"` -ge `wc -l < "expout"`])

    AT_CHECK(
      [[sed '
s/ (xid=0x[0-9a-fA-F]*)//
s/ *duration.*//
s/00:0.$/00:0x/' < monitor.log]],
      [0], [expout])
}

# It's a service connection so initially there should be no async messages.
check_async 1

# Set miss_send_len to 128, turning on packet-ins for our service connection.
ovs-appctl -t ovs-ofctl ofctl/send 0409000c0123456700000080
check_async 2 OFPR_ACTION OFPPR_ADD OFPPR_DELETE OFPRR_DELETE OFPRR_GROUP_DELETE

# Become secondary (OF 1.3), which should disable everything except port status.
ovs-appctl -t ovs-ofctl ofctl/send 041800180000000200000003000000000000000000000001
check_async 3 OFPPR_ADD OFPPR_DELETE

# Use OF 1.3 OFPT_SET_ASYNC to enable a patchwork of asynchronous messages.
ovs-appctl -t ovs-ofctl ofctl/send 041c00200000000200000002000000050000000500000002000000020000000d
check_async 4 OFPR_INVALID_TTL OFPPR_DELETE OFPRR_DELETE OFPRR_GROUP_DELETE

# Set controller ID 123.
ovs-appctl -t ovs-ofctl ofctl/send 04040018000000030000232000000014000000000000007b
check_async 5 OFPR_NO_MATCH OFPPR_DELETE OFPRR_DELETE OFPRR_GROUP_DELETE

# Restore controller ID 0.
ovs-appctl -t ovs-ofctl ofctl/send 040400180000000300002320000000140000000000000000

# Become primary (OF 1.3).
ovs-appctl -t ovs-ofctl ofctl/send 041800180000000400000002000000000000000000000002
check_async 6 OFPR_ACTION OFPPR_ADD

OVS_APP_EXIT_AND_WAIT([ovs-ofctl])
OVS_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([ofproto - asynchronous message control (OpenFlow 1.4)])
OVS_VSWITCHD_START([dnl
    add-port br0 p1 -- set Interface p1 type=dummy ofport_request=10
])
AT_CHECK([ovs-ofctl -O OpenFlow14 -P standard monitor br0 --detach --no-chdir --pidfile])
ovs_appctl () {
    echo ovs-appctl "$@"
    AT_CHECK([ovs-appctl "$@"], [0], [ignore], [ignore])
}
ovs_ofctl () {
    echo ovs-ofctl --no-names "$@"
    AT_CHECK([ovs-ofctl --no-names "$@"])
}
ovs_vsctl () {
    echo ovs-vsctl "$@"
    AT_CHECK([ovs-vsctl "$@"])
}
check_async () {
    printf '\n\n--- check_async %d ---\n\n\n' $1
    INDEX=$1
    shift

    ovs_appctl -t ovs-ofctl ofctl/barrier
    ovs_appctl -t ovs-ofctl ofctl/set-output-file monitor.log
    : > expout

    # OFPT_PACKET_IN, OFPR_PACKET_OUT (controller_id=0)
    ovs_ofctl -O OpenFlow14 packet-out br0 none controller '0001020304050010203040501234'
    if test X"$1" = X"OFPR_PACKET_OUT"; then shift;
        echo >>expout "OFPT_PACKET_IN (OF1.4): total_len=14 in_port=ANY (via packet_out) data_len=14 (unbuffered)
vlan_tci=0x0000,dl_src=00:10:20:30:40:50,dl_dst=00:01:02:03:04:05,dl_type=0x1234"
    fi

    # OFPT_PACKET_IN, OFPR_ACTION_SET (controller_id=0)
    ovs_ofctl -O OpenFlow14 add-flow br0 'in_port=10 actions=write_actions(output(CONTROLLER))'
    ovs_appctl netdev-dummy/receive p1 'in_port(10),eth(src=00:10:20:30:40:50,dst=00:01:02:03:04:05),eth_type(0x1234)'
    if test X"$1" = X"OFPR_ACTION_SET"; then shift;
        echo >>expout "OFPT_PACKET_IN (OF1.4): cookie=0x0 total_len=14 in_port=10 (via action_set) data_len=14 (unbuffered)
vlan_tci=0x0000,dl_src=00:10:20:30:40:50,dl_dst=00:01:02:03:04:05,dl_type=0x1234"
    fi

    # OFPT_PACKET_IN, OFPR_NO_MATCH (controller_id=123)
    ovs_ofctl -O OpenFlow14  packet-out br0 none 'controller(reason=no_match,id=123)' '0001020304050010203040501234'
    if test X"$1" = X"OFPR_NO_MATCH"; then shift;
        echo >>expout "OFPT_PACKET_IN (OF1.4): total_len=14 in_port=ANY (via no_match) data_len=14 (unbuffered)
vlan_tci=0x0000,dl_src=00:10:20:30:40:50,dl_dst=00:01:02:03:04:05,dl_type=0x1234"
    fi

    # OFPT_PACKET_IN, OFPR_INVALID_TTL (controller_id=0)
    ovs_ofctl -O OpenFlow14 packet-out br0 none dec_ttl '002583dfb4000026b98cb0f908004500003eb7e200000011339bac11370dac100002d7730035002b8f6d86fb0100000100000000000006626c702d7873066e696369726103636f6d00000f00'
    if test X"$1" = X"OFPR_INVALID_TTL"; then shift;
        echo >>expout "OFPT_PACKET_IN (OF1.4): total_len=76 in_port=ANY (via invalid_ttl) data_len=76 (unbuffered)
udp,vlan_tci=0x0000,dl_src=00:26:b9:8c:b0:f9,dl_dst=00:25:83:df:b4:00,nw_src=172.17.55.13,nw_dst=172.16.0.2,nw_tos=0,nw_ecn=0,nw_ttl=0,nw_frag=no,tp_src=55155,tp_dst=53 udp_csum:8f6d"
    fi

# OFPT_PORT_STATUS, OFPPR_ADD
    ovs_vsctl add-port br0 test -- set Interface test type=dummy
    if test X"$1" = X"OFPPR_ADD"; then shift;
        echo >>expout "OFPT_PORT_STATUS (OF1.4): ADD: ${INDEX}(test): addr:aa:55:aa:55:00:0x
     config:     0
     state:      0
     speed: 0 Mbps now, 0 Mbps max
OFPT_PORT_STATUS (OF1.4): MOD: ${INDEX}(test): addr:aa:55:aa:55:00:0x
     config:     0
     state:      LIVE
     speed: 0 Mbps now, 0 Mbps max"
    fi

    # OFPT_PORT_STATUS, OFPPR_MODIFY
    ovs_ofctl -O OpenFlow14 -vwarn mod-port br0 test down
    if test X"$1" = X"OFPPR_MODIFY"; then shift;
        echo >>expout "OFPT_PORT_STATUS (OF1.4): MOD: ${INDEX}(test): addr:aa:55:aa:55:00:0x
     config:     PORT_DOWN
     state:      0
     speed: 0 Mbps now, 0 Mbps max
OFPT_PORT_STATUS (OF1.4): MOD: ${INDEX}(test): addr:aa:55:aa:55:00:0x
     config:     PORT_DOWN
     state:      LINK_DOWN
     speed: 0 Mbps now, 0 Mbps max"
    fi

    # OFPT_PORT_STATUS, OFPPR_DELETE
    ovs_vsctl del-port br0 test
    if test X"$1" = X"OFPPR_DELETE"; then shift;
        echo >>expout "OFPT_PORT_STATUS (OF1.4): DEL: ${INDEX}(test): addr:aa:55:aa:55:00:0x
     config:     PORT_DOWN
     state:      LINK_DOWN
     speed: 0 Mbps now, 0 Mbps max"
    fi

    # OFPT_FLOW_REMOVED, OFPRR_DELETE
    ovs_ofctl -O OpenFlow14 add-flow br0 send_flow_rem,actions=drop
    ovs-ofctl -O OpenFlow14 dump-flows br0
    ovs_ofctl -O OpenFlow14 --strict del-flows br0 ''
    ovs-ofctl -O OpenFlow14 dump-flows br0
    if test X"$1" = X"OFPRR_DELETE"; then shift;
        echo >>expout "OFPT_FLOW_REMOVED (OF1.4):  reason=delete table_id=0"
    fi

    # OFPT_FLOW_REMOVED, OFPRR_GROUP_DELETE
    ovs_ofctl -O OpenFlow14 add-group br0 group_id=1234,type=all,bucket=output:10
    ovs_ofctl -O OpenFlow14 add-flow br0 send_flow_rem,actions=group:1234
    ovs_ofctl -O OpenFlow14 --strict del-groups br0 group_id=1234
    if test X"$1" = X"OFPRR_GROUP_DELETE"; then shift;
        echo >>expout "OFPT_FLOW_REMOVED (OF1.4):  reason=group_delete table_id=0"
    fi

    # OFPT_TABLE_STATUS, OFPTR_VACANCY_UP
    if test X"$1" = X"OFPTR_VACANCY_UP"; then shift;
        AT_CHECK([ovs-vsctl -- --id=@t1 create Flow_Table flow-limit=10 -- set bridge br0 flow_tables:1=@t1], [0], [ignore], [])

        # Turn on vacancy events, then add flows until we're full.
        # With initial vacancy of 100% and vacancy_up of 80%, so that
        # vacancy >= vacancy_up, this enables VACANY_DOWN events, so
        # we get a single such message when vacancy dips below 20%.
        ovs_ofctl -O OpenFlow14 mod-table br0 1 vacancy:20,80
        ovs_ofctl -O OpenFlow14 add-flow br0 table=1,in_port=1,actions=2
        ovs_ofctl -O OpenFlow14 add-flow br0 table=1,in_port=2,actions=2
        ovs_ofctl -O OpenFlow14 add-flow br0 table=1,in_port=3,actions=2
        ovs_ofctl -O OpenFlow14 add-flow br0 table=1,in_port=4,actions=2
        ovs_ofctl -O OpenFlow14 add-flow br0 table=1,in_port=5,actions=2
        ovs_ofctl -O OpenFlow14 add-flow br0 table=1,in_port=6,actions=2
        ovs_ofctl -O OpenFlow14 add-flow br0 table=1,in_port=7,actions=2
        ovs_ofctl -O OpenFlow14 add-flow br0 table=1,in_port=8,actions=2
        ovs_ofctl -O OpenFlow14 add-flow br0 table=1,in_port=9,actions=2
        ovs_ofctl -O OpenFlow14 add-flow br0 table=1,in_port=10,actions=2
        echo >>expout "OFPT_TABLE_STATUS (OF1.4): reason=VACANCY_DOWN
table_desc:-
  table 1:
   eviction=off eviction_flags=OTHER|IMPORTANCE|LIFETIME
   vacancy=on vacancy_down=20% vacancy_up=80% vacancy=10%"
        # Then delete flows until we're empty.  Sending the
        # VACANCY_DOWN message enabled VACANCY_UP events, so we get a
        # single such message when vacancy rises above 80%.
        ovs_ofctl -O OpenFlow14 del-flows br0 table=1,in_port=1
        ovs_ofctl -O OpenFlow14 del-flows br0 table=1,in_port=2
        ovs_ofctl -O OpenFlow14 del-flows br0 table=1,in_port=3
        ovs_ofctl -O OpenFlow14 del-flows br0 table=1,in_port=4
        ovs_ofctl -O OpenFlow14 del-flows br0 table=1,in_port=5
        ovs_ofctl -O OpenFlow14 del-flows br0 table=1,in_port=6
        ovs_ofctl -O OpenFlow14 del-flows br0 table=1,in_port=7
        ovs_ofctl -O OpenFlow14 del-flows br0 table=1,in_port=8
        ovs_ofctl -O OpenFlow14 del-flows br0 table=1,in_port=9
        ovs_ofctl -O OpenFlow14 del-flows br0 table=1,in_port=10
        echo >>expout "OFPT_TABLE_STATUS (OF1.4): reason=VACANCY_UP
table_desc:-
  table 1:
   eviction=off eviction_flags=OTHER|IMPORTANCE|LIFETIME
   vacancy=on vacancy_down=20% vacancy_up=80% vacancy=90%"

        # Now approach vacancy from the other direction.  First
        # disable vacancy events.  With initial vacancy of 70%, so
        # that vacancy < vacancy_up, this enables VACANCY_UP events.
        # That means that filling up the table generates no message,
        # but deleting all the flows generates VACANCY_UP at the point
        # vacancy rises above 80%.
        ovs_ofctl -O OpenFlow14 mod-table br0 1 novacancy
        ovs_ofctl -O OpenFlow14 add-flow br0 table=1,in_port=1,actions=2
        ovs_ofctl -O OpenFlow14 add-flow br0 table=1,in_port=2,actions=2
        ovs_ofctl -O OpenFlow14 add-flow br0 table=1,in_port=3,actions=2
        ovs_ofctl -O OpenFlow14 mod-table br0 1 vacancy:20,80
        ovs_ofctl -O OpenFlow14 add-flow br0 table=1,in_port=4,actions=2
        ovs_ofctl -O OpenFlow14 add-flow br0 table=1,in_port=5,actions=2
        ovs_ofctl -O OpenFlow14 add-flow br0 table=1,in_port=6,actions=2
        ovs_ofctl -O OpenFlow14 add-flow br0 table=1,in_port=7,actions=2
        ovs_ofctl -O OpenFlow14 add-flow br0 table=1,in_port=8,actions=2
        ovs_ofctl -O OpenFlow14 add-flow br0 table=1,in_port=9,actions=2
        ovs_ofctl -O OpenFlow14 add-flow br0 table=1,in_port=10,actions=2
        ovs_ofctl -O OpenFlow14 del-flows br0 table=1,in_port=1
        ovs_ofctl -O OpenFlow14 del-flows br0 table=1,in_port=2
        ovs_ofctl -O OpenFlow14 del-flows br0 table=1,in_port=3
        ovs_ofctl -O OpenFlow14 del-flows br0 table=1,in_port=4
        ovs_ofctl -O OpenFlow14 del-flows br0 table=1,in_port=5
        ovs_ofctl -O OpenFlow14 del-flows br0 table=1,in_port=6
        ovs_ofctl -O OpenFlow14 del-flows br0 table=1,in_port=7
        ovs_ofctl -O OpenFlow14 del-flows br0 table=1,in_port=8
        ovs_ofctl -O OpenFlow14 del-flows br0 table=1,in_port=9
        ovs_ofctl -O OpenFlow14 del-flows br0 table=1,in_port=10
        echo >>expout "OFPT_TABLE_STATUS (OF1.4): reason=VACANCY_UP
table_desc:-
  table 1:
   eviction=off eviction_flags=OTHER|IMPORTANCE|LIFETIME
   vacancy=on vacancy_down=20% vacancy_up=80% vacancy=90%"
    fi

    AT_FAIL_IF([test X"$1" != X])

    normalize_log () {
       sed '
s/ (xid=0x[[0-9a-fA-F]]*)//
s/ *duration.*//
s/00:0.$/00:0x/' < monitor.log
    }

    OVS_WAIT_UNTIL([test `wc -l < "monitor.log"` -ge `wc -l < "expout"`],
                   [normalize_log | diff -u - expout])

    AT_CHECK(
      [normalize_log],
      [0], [expout])
}

# It's a service connection so initially there should be no async messages.
check_async 1

# Set miss_send_len to 128, turning on packet-ins for our service connection.
ovs_appctl -t ovs-ofctl ofctl/send 0509000c0123456700000080
check_async 2 OFPR_PACKET_OUT OFPR_ACTION_SET OFPPR_ADD OFPPR_MODIFY OFPPR_DELETE OFPRR_DELETE OFPRR_GROUP_DELETE

# Become secondary (OF 1.4), which should disable everything except port status.
ovs_appctl -t ovs-ofctl ofctl/send 051800180000000200000003000000000000000000000001
check_async 3 OFPPR_ADD OFPPR_MODIFY OFPPR_DELETE

# Use OF 1.4 OFPT_SET_ASYNC to enable a patchwork of asynchronous messages.
ovs_appctl -t ovs-ofctl ofctl/send 051c0040000000020000000800000005000100080000002000020008000000020003000800000005000400080000001c00050008000000050008000800000018
check_async 4 OFPR_INVALID_TTL OFPPR_DELETE OFPRR_DELETE OFPRR_GROUP_DELETE OFPTR_VACANCY_UP

# Set controller ID 123.
ovs_appctl -t ovs-ofctl ofctl/send 05040018000000030000232000000014000000000000007b
check_async 5 OFPR_NO_MATCH OFPPR_DELETE OFPRR_DELETE OFPRR_GROUP_DELETE

# Restore controller ID 0.
ovs_appctl -t ovs-ofctl ofctl/send 050400180000000300002320000000140000000000000000

# Become primary (OF 1.4).
ovs_appctl -t ovs-ofctl ofctl/send 051800180000000400000002000000000000000000000002
check_async 6 OFPR_PACKET_OUT OFPPR_ADD OFPPR_MODIFY OFPRR_DELETE

OVS_APP_EXIT_AND_WAIT([ovs-ofctl])
OVS_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([ofproto - asynchronous message control (OpenFlow 1.5)])
OVS_VSWITCHD_START
AT_CHECK([ovs-ofctl -O OpenFlow15 -P standard monitor br0 --detach --no-chdir --pidfile])
check_async () {
    printf '\n\n--- check_async %d ---\n\n\n' $1
    INDEX=$1
    shift

    ovs-appctl -t ovs-ofctl ofctl/barrier
    ovs-appctl -t ovs-ofctl ofctl/set-output-file monitor.log
    : > expout

    # Other tests are not working with OF 1.5, and message
    # format may change, so leave them out.

    # OFPT_PORT_STATUS, OFPPR_ADD
    ovs-vsctl add-port br0 test -- set Interface test type=dummy
    if test X"$1" = X"OFPPR_ADD"; then shift;
        echo >>expout "OFPT_PORT_STATUS (OF1.5): ADD: ${INDEX}(test): addr:aa:55:aa:55:00:0x
     config:     0
     state:      0
     speed: 0 Mbps now, 0 Mbps max
OFPT_PORT_STATUS (OF1.5): MOD: ${INDEX}(test): addr:aa:55:aa:55:00:0x
     config:     0
     state:      LIVE
     speed: 0 Mbps now, 0 Mbps max"
    fi

    # OFPT_PORT_STATUS, OFPPR_MODIFY
    ovs-ofctl -O OpenFlow15 -vwarn mod-port br0 test down
    if test X"$1" = X"OFPPR_MODIFY"; then shift;
        echo >>expout "OFPT_PORT_STATUS (OF1.5): MOD: ${INDEX}(test): addr:aa:55:aa:55:00:0x
     config:     PORT_DOWN
     state:      0
     speed: 0 Mbps now, 0 Mbps max
OFPT_PORT_STATUS (OF1.5): MOD: ${INDEX}(test): addr:aa:55:aa:55:00:0x
     config:     PORT_DOWN
     state:      LINK_DOWN
     speed: 0 Mbps now, 0 Mbps max"
    fi

    # OFPT_PORT_STATUS, OFPPR_DELETE
    ovs-vsctl del-port br0 test
    if test X"$1" = X"OFPPR_DELETE"; then shift;
        echo >>expout "OFPT_PORT_STATUS (OF1.5): DEL: ${INDEX}(test): addr:aa:55:aa:55:00:0x
     config:     PORT_DOWN
     state:      LINK_DOWN
     speed: 0 Mbps now, 0 Mbps max"
    fi

    AT_FAIL_IF([test X"$1" != X])

    OVS_WAIT_UNTIL([test `wc -l < "monitor.log"` -ge `wc -l < "expout"`])

    AT_CHECK(
      [[sed '
s/ (xid=0x[0-9a-fA-F]*)//
s/ *duration.*//
s/00:0.$/00:0x/' < monitor.log]],
      [0], [expout])
}

# It's a service connection so initially there should be no async messages.
check_async 1

# If we don't set this, async messages are not received.
# Set miss_send_len to 128, turning on packet-ins for our service connection.
ovs-appctl -t ovs-ofctl ofctl/send 0609000c0123456700000080
check_async 2 OFPPR_ADD OFPPR_MODIFY OFPPR_DELETE

# Set-async has changed in OF 1.4 and is not yet implemented.

OVS_APP_EXIT_AND_WAIT([ovs-ofctl])
OVS_VSWITCHD_STOP
AT_CLEANUP

dnl This test checks that the role request/response messaging works
dnl and that generation_id is handled properly.
AT_SETUP([ofproto - controller role (OpenFlow 1.2)])
OVS_VSWITCHD_START
on_exit 'kill `cat c1.pid c2.pid`'

# Start two ovs-ofctl controller processes.
AT_CAPTURE_FILE([monitor1.log])
AT_CAPTURE_FILE([expout1])
AT_CAPTURE_FILE([experr1])
AT_CAPTURE_FILE([monitor2.log])
AT_CAPTURE_FILE([expout2])
AT_CAPTURE_FILE([experr2])
for i in 1 2; do
     AT_CHECK([ovs-ofctl -O OpenFlow12 monitor br0 --detach --no-chdir --pidfile=c$i.pid --unixctl=c$i])
    ovs-appctl -t `pwd`/c$i ofctl/barrier
    ovs-appctl -t `pwd`/c$i ofctl/set-output-file monitor$i.log
    : > expout$i
    : > experr$i

    # find out current role
    ovs-appctl -t `pwd`/c$i ofctl/send 031800180000000200000000000000000000000000000000
    echo >>experr$i "send: OFPT_ROLE_REQUEST (OF1.2): role=nochange"
    echo >>expout$i "OFPT_ROLE_REPLY (OF1.2): role=equal"
done

# controller 1: Become secondary (generation_id is initially undefined, so
# 2^63+2 should not be stale)
ovs-appctl -t `pwd`/c1 ofctl/send 031800180000000300000003000000008000000000000002
echo >>experr1 "send: OFPT_ROLE_REQUEST (OF1.2): role=secondary generation_id=9223372036854775810"
echo >>expout1 "OFPT_ROLE_REPLY (OF1.2): role=secondary generation_id=9223372036854775810"

# controller 2: Become primary.
ovs-appctl -t `pwd`/c2 ofctl/send 031800180000000300000002000000008000000000000003
echo >>experr2 "send: OFPT_ROLE_REQUEST (OF1.2): role=primary generation_id=9223372036854775811"
echo >>expout2 "OFPT_ROLE_REPLY (OF1.2): role=primary generation_id=9223372036854775811"

# controller 1: Try to become the primary using a stale generation ID
ovs-appctl -t `pwd`/c1 ofctl/send 031800180000000400000002000000000000000000000003
echo >>experr1 "send: OFPT_ROLE_REQUEST (OF1.2): role=primary generation_id=3"
echo >>expout1 "OFPT_ERROR (OF1.2): OFPRRFC_STALE"
echo >>expout1 "OFPT_ROLE_REQUEST (OF1.2): role=primary generation_id=3"

# controller 1: Become primary using a valid generation ID
ovs-appctl -t `pwd`/c1 ofctl/send 031800180000000500000002000000000000000000000001
echo >>experr1 "send: OFPT_ROLE_REQUEST (OF1.2): role=primary generation_id=1"
echo >>expout1 "OFPT_ROLE_REPLY (OF1.2): role=primary generation_id=1"

for i in 1 2; do
    ovs-appctl -t `pwd`/c$i ofctl/barrier
    echo >>expout$i "OFPT_BARRIER_REPLY (OF1.2):"
done

# Check output.
for i in 1 2; do
    cp expout$i expout
    AT_CHECK([grep -v '^send:' monitor$i.log | strip_xids], [0], [expout])
    cp experr$i expout
    AT_CHECK([grep '^send:' monitor$i.log | strip_xids], [0], [expout])
done
OVS_VSWITCHD_STOP
AT_CLEANUP

dnl This test checks that the role request/response messaging works,
dnl that generation_id is handled properly, and that role status update
dnl messages are sent when a controller's role gets changed from primary
dnl to secondary.
AT_SETUP([ofproto - controller role (OpenFlow 1.4)])
OVS_VSWITCHD_START
on_exit 'kill `cat c1.pid c2.pid`'

# Start two ovs-ofctl controller processes.
AT_CAPTURE_FILE([monitor1.log])
AT_CAPTURE_FILE([expout1])
AT_CAPTURE_FILE([experr1])
AT_CAPTURE_FILE([monitor2.log])
AT_CAPTURE_FILE([expout2])
AT_CAPTURE_FILE([experr2])
for i in 1 2; do
     AT_CHECK([ovs-ofctl -O OpenFlow14 monitor br0 --detach --no-chdir --pidfile=c$i.pid --unixctl=c$i])
    ovs-appctl -t `pwd`/c$i ofctl/barrier
    ovs-appctl -t `pwd`/c$i ofctl/set-output-file monitor$i.log
    : > expout$i
    : > experr$i

    # find out current role
    ovs-appctl -t `pwd`/c$i ofctl/send 051800180000000200000000000000000000000000000000
    echo >>experr$i "send: OFPT_ROLE_REQUEST (OF1.4): role=nochange"
    echo >>expout$i "OFPT_ROLE_REPLY (OF1.4): role=equal"
done

# controller 1: Become secondary (generation_id is initially undefined, so
# 2^63+2 should not be stale)
ovs-appctl -t `pwd`/c1 ofctl/send 051800180000000300000003000000008000000000000002
echo >>experr1 "send: OFPT_ROLE_REQUEST (OF1.4): role=secondary generation_id=9223372036854775810"
echo >>expout1 "OFPT_ROLE_REPLY (OF1.4): role=secondary generation_id=9223372036854775810"

# controller 2: Become primary.
ovs-appctl -t `pwd`/c2 ofctl/send 051800180000000300000002000000008000000000000003
echo >>experr2 "send: OFPT_ROLE_REQUEST (OF1.4): role=primary generation_id=9223372036854775811"
echo >>expout2 "OFPT_ROLE_REPLY (OF1.4): role=primary generation_id=9223372036854775811"

# controller 1: Try to become the primary using a stale generation ID
ovs-appctl -t `pwd`/c1 ofctl/send 051800180000000400000002000000000000000000000003
echo >>experr1 "send: OFPT_ROLE_REQUEST (OF1.4): role=primary generation_id=3"
echo >>expout1 "OFPT_ERROR (OF1.4): OFPRRFC_STALE"
echo >>expout1 "OFPT_ROLE_REQUEST (OF1.4): role=primary generation_id=3"

# controller 1: Become primary using a valid generation ID
ovs-appctl -t `pwd`/c1 ofctl/send 051800180000000500000002000000000000000000000001
echo >>experr1 "send: OFPT_ROLE_REQUEST (OF1.4): role=primary generation_id=1"
echo >>expout1 "OFPT_ROLE_REPLY (OF1.4): role=primary generation_id=1"
echo >>expout2 "OFPT_ROLE_STATUS (OF1.4): role=secondary generation_id=1 reason=primary_request"

for i in 1 2; do
    ovs-appctl -t `pwd`/c$i ofctl/barrier
    echo >>expout$i "OFPT_BARRIER_REPLY (OF1.4):"
done

# Check output.
for i in 1 2; do
    cp expout$i expout
    AT_CHECK([grep -v '^send:' monitor$i.log | strip_xids], [0], [expout])
    cp experr$i expout
    AT_CHECK([grep '^send:' monitor$i.log | strip_xids], [0], [expout])
done
OVS_VSWITCHD_STOP
AT_CLEANUP

dnl This test checks that the role request/response messaging works,
dnl that generation_id is handled properly, and that role status update
dnl messages are sent when a controller's role gets changed from primary
dnl to secondary.
AT_SETUP([ofproto - controller role (OpenFlow 1.3)])
OVS_VSWITCHD_START
on_exit 'kill `cat c1.pid c2.pid`'

# Start two ovs-ofctl controller processes.
AT_CAPTURE_FILE([monitor1.log])
AT_CAPTURE_FILE([expout1])
AT_CAPTURE_FILE([experr1])
AT_CAPTURE_FILE([monitor2.log])
AT_CAPTURE_FILE([expout2])
AT_CAPTURE_FILE([experr2])
for i in 1 2; do
     AT_CHECK([ovs-ofctl -O OpenFlow13 monitor br0 --detach --no-chdir --pidfile=c$i.pid --unixctl=c$i])
    ovs-appctl -t `pwd`/c$i ofctl/barrier
    ovs-appctl -t `pwd`/c$i ofctl/set-output-file monitor$i.log
    : > expout$i
    : > experr$i

    # find out current role
    ovs-appctl -t `pwd`/c$i ofctl/send 041800180000000200000000000000000000000000000000
    echo >>experr$i "send: OFPT_ROLE_REQUEST (OF1.3): role=nochange"
    echo >>expout$i "OFPT_ROLE_REPLY (OF1.3): role=equal"
done

# controller 1: Become secondary (generation_id is initially undefined, so
# 2^63+2 should not be stale)
ovs-appctl -t `pwd`/c1 ofctl/send 041800180000000300000003000000008000000000000002
echo >>experr1 "send: OFPT_ROLE_REQUEST (OF1.3): role=secondary generation_id=9223372036854775810"
echo >>expout1 "OFPT_ROLE_REPLY (OF1.3): role=secondary generation_id=9223372036854775810"

# controller 2: Become primary.
ovs-appctl -t `pwd`/c2 ofctl/send 041800180000000300000002000000008000000000000003
echo >>experr2 "send: OFPT_ROLE_REQUEST (OF1.3): role=primary generation_id=9223372036854775811"
echo >>expout2 "OFPT_ROLE_REPLY (OF1.3): role=primary generation_id=9223372036854775811"

# controller 1: Try to become the primary using a stale generation ID
ovs-appctl -t `pwd`/c1 ofctl/send 041800180000000400000002000000000000000000000003
echo >>experr1 "send: OFPT_ROLE_REQUEST (OF1.3): role=primary generation_id=3"
echo >>expout1 "OFPT_ERROR (OF1.3): OFPRRFC_STALE"
echo >>expout1 "OFPT_ROLE_REQUEST (OF1.3): role=primary generation_id=3"

# controller 1: Become primary using a valid generation ID
ovs-appctl -t `pwd`/c1 ofctl/send 041800180000000500000002000000000000000000000001
echo >>experr1 "send: OFPT_ROLE_REQUEST (OF1.3): role=primary generation_id=1"
echo >>expout1 "OFPT_ROLE_REPLY (OF1.3): role=primary generation_id=1"
echo >>expout2 "ONFT_ROLE_STATUS (OF1.3): role=secondary generation_id=1 reason=primary_request"

for i in 1 2; do
    ovs-appctl -t `pwd`/c$i ofctl/barrier
    echo >>expout$i "OFPT_BARRIER_REPLY (OF1.3):"
done

# Check output.
for i in 1 2; do
    cp expout$i expout
    AT_CHECK([grep -v '^send:' monitor$i.log | strip_xids], [0], [expout])
    cp experr$i expout
    AT_CHECK([grep '^send:' monitor$i.log | strip_xids], [0], [expout])
done
OVS_VSWITCHD_STOP
AT_CLEANUP

dnl This test checks the Group and meter notifications when a group mod
dnl command is sent from one controller and the reply is received by
dnl other controllers.
AT_SETUP([ofproto - requestforward (OpenFlow 1.4)])
OVS_VSWITCHD_START
on_exit 'kill `cat c1.pid c2.pid c3.pid`'

# Start two ovs-ofctl controller processes.
AT_CAPTURE_FILE([monitor1.log])
AT_CAPTURE_FILE([expout1])
AT_CAPTURE_FILE([monitor2.log])
AT_CAPTURE_FILE([expout2])
AT_CAPTURE_FILE([monitor3.log])
AT_CAPTURE_FILE([expout3])

ovs-ofctl -O OpenFlow15 monitor br0 --detach --no-chdir --pidfile=c1.pid --unixctl=c1
ovs-ofctl -O OpenFlow14 monitor br0 --detach --no-chdir --pidfile=c2.pid --unixctl=c2
ovs-ofctl -O OpenFlow14 monitor br0 --detach --no-chdir --pidfile=c3.pid --unixctl=c3

check_async () {
    for i in 1 3; do
        ovs-appctl -t `pwd`/c$i ofctl/barrier
        ovs-appctl -t `pwd`/c$i ofctl/set-output-file monitor$i.log
        : > expout$i
    done

    printf '\n\n--- check_async %d ---\n\n\n' $1
    INDEX=$1
    shift

    # OFPGC_ADD
    ovs-appctl -t `pwd`/c2 ofctl/send "050f0020000000020000000000000001 00100000 ffffffffffffffff 00000000"
    if test X"$1" = X"OFPGC_ADD"; then shift;
        echo >>expout2 "send: OFPT_GROUP_MOD (OF1.4):
 ADD group_id=1,type=all,bucket=actions=drop"
        echo >>expout1 "OFPT_REQUESTFORWARD (OF1.5): reason=group_mod
 ADD group_id=1,type=all,bucket=bucket_id:0,actions=drop"
        echo >>expout3 "OFPT_REQUESTFORWARD (OF1.4): reason=group_mod
 ADD group_id=1,type=all,bucket=actions=drop"
    fi

    # OFPGC_MODIFY
    ovs-appctl -t `pwd`/c2 ofctl/send "050f0020000000020001010000000001 00100000 ffffffffffffffff 00000000"
    if test X"$1" = X"OFPGC_MODIFY"; then shift;
        echo >>expout2 "send: OFPT_GROUP_MOD (OF1.4):
 MOD group_id=1,type=select,bucket=weight:0,actions=drop"
        echo >>expout1 "OFPT_REQUESTFORWARD (OF1.5): reason=group_mod
 MOD group_id=1,type=select,bucket=bucket_id:0,weight:0,actions=drop"
        echo >>expout3 "OFPT_REQUESTFORWARD (OF1.4): reason=group_mod
 MOD group_id=1,type=select,bucket=weight:0,actions=drop"
    fi

    ovs-appctl -t `pwd`/c1 ofctl/barrier
    echo >>expout1 "OFPT_BARRIER_REPLY (OF1.5):"
    ovs-appctl -t `pwd`/c2 ofctl/barrier
    echo >>expout2 "OFPT_BARRIER_REPLY (OF1.4):"
    ovs-appctl -t `pwd`/c3 ofctl/barrier
    echo >>expout3 "OFPT_BARRIER_REPLY (OF1.4):"

    # Check output.
    for i in 1 3; do
        cp expout$i expout
        AT_CHECK(
      [[sed '
s/ (xid=0x[0-9a-fA-F]*)//'< monitor$i.log]],
      [0], [expout])
    done
}

# controller 1: Become secondary
ovs-appctl -t `pwd`/c1 ofctl/send 061800180000000300000003000000008000000000000002

# controller 2: Become primary
ovs-appctl -t `pwd`/c2 ofctl/send 051800180000000300000002000000008000000000000003

# controller 1: Become secondary
ovs-appctl -t `pwd`/c3 ofctl/send 051800180000000300000003000000008000000000000004

# controller 1: Enabled requestforward using set Asynchronous message
ovs-appctl -t `pwd`/c1 ofctl/send 061c00280000000200000008000000050002000800000002000400080000001a000a000800000003

# controller 2: Enabled requestforward using set Asynchronous message
ovs-appctl -t `pwd`/c2 ofctl/send 051c002800000002000100080000000200030008000000050005000800000005000b000800000003

# controller 1: Enabled requestforward using set Asynchronous message
ovs-appctl -t `pwd`/c3 ofctl/send 051c00280000000200000008000000050002000800000002000400080000001a000a000800000003
check_async 1 OFPGC_ADD OFPGC_MODIFY

OVS_VSWITCHD_STOP
AT_CLEANUP

dnl This test checks the backwards compatibility of the NXT_REQUESTFORWARD
dnl message type to OpenFlow 1.0, also relying on the Nicira Extensions:
dnl NXT_GROUP_MOD, NXT_ROLE_REQUEST, and OFPRAW_NXT_SET_ASYNC_CONFIG2,
dnl while also testing the functionality of the previous test.
AT_SETUP([ofproto - NXT requestforward (OpenFlow 1.0)])
OVS_VSWITCHD_START
on_exit 'kill `cat c1.pid c2.pid c3.pid`'

# Start two ovs-ofctl controller processes.
AT_CAPTURE_FILE([monitor1.log])
AT_CAPTURE_FILE([expout1])
AT_CAPTURE_FILE([monitor2.log])
AT_CAPTURE_FILE([expout2])
AT_CAPTURE_FILE([monitor3.log])
AT_CAPTURE_FILE([expout3])

ovs-ofctl -O OpenFlow10 monitor br0 --detach --no-chdir --pidfile=c1.pid --unixctl=c1
ovs-ofctl -O OpenFlow10 monitor br0 --detach --no-chdir --pidfile=c2.pid --unixctl=c2
ovs-ofctl -O OpenFlow10 monitor br0 --detach --no-chdir --pidfile=c3.pid --unixctl=c3

check_async () {
    for i in 1 3; do
        ovs-appctl -t `pwd`/c$i ofctl/barrier
        ovs-appctl -t `pwd`/c$i ofctl/set-output-file monitor$i.log
        : > expout$i
    done

    printf '\n\n--- check_async %d ---\n\n\n' $1
    INDEX=$1
    shift

    # OFPGC_ADD
    # NXT_GROUP_MOD (xid=0x2):
    # ADD group_id=2271560481,type=select,selection_method=hash,selection_method_param=7,bucket=bucket_id:0,weight:100,watch_port:1,actions=output:1,bucket=bucket_id:1,weight:200,watch_port:2,actions=output:2,bucket=bucket_id:2,weight:200,watch_port:3,actions=output:3
    ovs-appctl -t `pwd`/c2 ofctl/send "01 04 00 a8 00 00 00 02 00 00 23 20 00 00 00 1f 00 00 01 00 87 65 43 21 00 60 00 00 ff ff ff ff 00 20 00 08 00 00 00 00 00 00 00 08 00 01 00 00 00 00 00 08 00 64 00 00 00 01 00 08 00 00 00 01 00 20 00 08 00 00 00 01 00 00 00 08 00 02 00 00 00 00 00 08 00 c8 00 00 00 01 00 08 00 00 00 02 00 20 00 08 00 00 00 02 00 00 00 08 00 03 00 00 00 00 00 08 00 c8 00 00 00 01 00 08 00 00 00 03 ff ff 00 28 00 00 15 40 00 00 00 01 00 00 00 00 68 61 73 68 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 07"
    if test X"$1" = X"OFPGC_ADD"; then shift;
        echo >>expout2 "send: NXT_GROUP_MOD:
 ADD group_id=2271560481,type=select,selection_method=hash,selection_method_param=7,bucket=bucket_id:0,weight:100,watch_port:1,actions=output:1,bucket=bucket_id:1,weight:200,watch_port:2,actions=output:2,bucket=bucket_id:2,weight:200,watch_port:3,actions=output:3"
        echo >>expout1 "NXT_REQUESTFORWARD: reason=group_mod
 ADD group_id=2271560481,type=select,selection_method=hash,selection_method_param=7,bucket=bucket_id:0,weight:100,watch_port:1,actions=output:1,bucket=bucket_id:1,weight:200,watch_port:2,actions=output:2,bucket=bucket_id:2,weight:200,watch_port:3,actions=output:3"
        echo >>expout3 "NXT_REQUESTFORWARD: reason=group_mod
 ADD group_id=2271560481,type=select,selection_method=hash,selection_method_param=7,bucket=bucket_id:0,weight:100,watch_port:1,actions=output:1,bucket=bucket_id:1,weight:200,watch_port:2,actions=output:2,bucket=bucket_id:2,weight:200,watch_port:3,actions=output:3"
    fi

    # OFPGC_MODIFY
    # NXT_GROUP_MOD (xid=0x2):
    # MOD group_id=2271560481,type=select,selection_method=hash,selection_method_param=7,bucket=bucket_id:0,weight:150,watch_port:1,actions=output:1,bucket=bucket_id:1,weight:150,watch_port:2,actions=output:2,bucket=bucket_id:2,weight:150,watch_port:3,actions=output:3
    ovs-appctl -t `pwd`/c2 ofctl/send "01 04 00 a8 00 00 00 02 00 00 23 20 00 00 00 1f 00 01 01 00 87 65 43 21 00 60 00 00 ff ff ff ff 00 20 00 08 00 00 00 00 00 00 00 08 00 01 00 00 00 00 00 08 00 96 00 00 00 01 00 08 00 00 00 01 00 20 00 08 00 00 00 01 00 00 00 08 00 02 00 00 00 00 00 08 00 96 00 00 00 01 00 08 00 00 00 02 00 20 00 08 00 00 00 02 00 00 00 08 00 03 00 00 00 00 00 08 00 96 00 00 00 01 00 08 00 00 00 03 ff ff 00 28 00 00 15 40 00 00 00 01 00 00 00 00 68 61 73 68 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 07"
    if test X"$1" = X"OFPGC_MODIFY"; then shift;
        echo >>expout2 "send: NXT_GROUP_MOD:
 MOD group_id=2271560481,type=select,selection_method=hash,selection_method_param=7,bucket=bucket_id:0,weight:150,watch_port:1,actions=output:1,bucket=bucket_id:1,weight:150,watch_port:2,actions=output:2,bucket=bucket_id:2,weight:150,watch_port:3,actions=output:3"
        echo >>expout1 "NXT_REQUESTFORWARD: reason=group_mod
 MOD group_id=2271560481,type=select,selection_method=hash,selection_method_param=7,bucket=bucket_id:0,weight:150,watch_port:1,actions=output:1,bucket=bucket_id:1,weight:150,watch_port:2,actions=output:2,bucket=bucket_id:2,weight:150,watch_port:3,actions=output:3"
        echo >>expout3 "NXT_REQUESTFORWARD: reason=group_mod
 MOD group_id=2271560481,type=select,selection_method=hash,selection_method_param=7,bucket=bucket_id:0,weight:150,watch_port:1,actions=output:1,bucket=bucket_id:1,weight:150,watch_port:2,actions=output:2,bucket=bucket_id:2,weight:150,watch_port:3,actions=output:3"
    fi

    ovs-appctl -t `pwd`/c1 ofctl/barrier
    echo >>expout1 "OFPT_BARRIER_REPLY:"
    ovs-appctl -t `pwd`/c2 ofctl/barrier
    echo >>expout2 "OFPT_BARRIER_REPLY:"
    ovs-appctl -t `pwd`/c3 ofctl/barrier
    echo >>expout3 "OFPT_BARRIER_REPLY:"

    # Check output.
    for i in 1 3; do
        cp expout$i expout
        AT_CHECK(
      [[sed '
s/ (xid=0x[0-9a-fA-F]*)//'< monitor$i.log]],
      [0], [expout])
    done
}

# controller 1: Become secondary
# NXT_ROLE_REQUEST (xid=0x3): role=secondary
ovs-appctl -t `pwd`/c1 ofctl/send 0104001400000003000023200000000a00000002

# controller 2: Become primary
# NXT_ROLE_REQUEST (xid=0x3): role=primary
ovs-appctl -t `pwd`/c2 ofctl/send 0104001400000003000023200000000a00000001

# controller 1: Become secondary
# NXT_ROLE_REQUEST (xid=0x3): role=secondary
ovs-appctl -t `pwd`/c3 ofctl/send 0104001400000003000023200000000a00000002

# controller 1: Enabled requestforward using OFPRAW_NXT_SET_ASYNC_CONFIG2
ovs-appctl -t `pwd`/c1 ofctl/send 0104003000000002000023200000001b00000008000000050002000800000002000400080000001a000a000800000003

# controller 2: Enabled requestforward using OFPRAW_NXT_SET_ASYNC_CONFIG2
ovs-appctl -t `pwd`/c2 ofctl/send 0104003000000002000023200000001b000100080000000200030008000000050005000800000005000b000800000003

# controller 1: Enabled requestforward using OFPRAW_NXT_SET_ASYNC_CONFIG2
ovs-appctl -t `pwd`/c3 ofctl/send 0104003000000002000023200000001b00000008000000050002000800000002000400080000001a000a000800000003
check_async 1 OFPGC_ADD OFPGC_MODIFY

OVS_VSWITCHD_STOP
AT_CLEANUP

dnl This test checks the Group and meter notifications when a group mod
dnl command is sent from one controller and the reply is received by
dnl other controllers, using the ONF Extension for OF 1.3.
AT_SETUP([ofproto - ONF requestforward (OpenFlow 1.3)])
OVS_VSWITCHD_START
on_exit 'kill `cat c1.pid c2.pid c3.pid`'

# Start two ovs-ofctl controller processes.
AT_CAPTURE_FILE([monitor1.log])
AT_CAPTURE_FILE([expout1])
AT_CAPTURE_FILE([monitor2.log])
AT_CAPTURE_FILE([expout2])
AT_CAPTURE_FILE([monitor3.log])
AT_CAPTURE_FILE([expout3])

ovs-ofctl -O OpenFlow13 monitor br0 --detach --no-chdir --pidfile=c1.pid --unixctl=c1
ovs-ofctl -O OpenFlow13 monitor br0 --detach --no-chdir --pidfile=c2.pid --unixctl=c2
ovs-ofctl -O OpenFlow13 monitor br0 --detach --no-chdir --pidfile=c3.pid --unixctl=c3

check_async () {
    for i in 1 3; do
        ovs-appctl -t `pwd`/c$i ofctl/barrier
        ovs-appctl -t `pwd`/c$i ofctl/set-output-file monitor$i.log
        : > expout$i
    done

    printf '\n\n--- check_async %d ---\n\n\n' $1
    INDEX=$1
    shift

    # OFPGC_ADD
    # OFPT_GROUP_MOD (OF1.3) (xid=0x2):
    # ADD group_id=1,type=all,bucket=actions=drop
    ovs-appctl -t `pwd`/c2 ofctl/send "040f0020000000020000000000000001 00100000 ffffffffffffffff 00000000"
    if test X"$1" = X"OFPGC_ADD"; then shift;
        echo >>expout2 "send: OFPT_GROUP_MOD (OF1.3):
 ADD group_id=1,type=all,bucket=actions=drop"
        echo >>expout1 "ONFT_REQUESTFORWARD (OF1.3): reason=group_mod
 ADD group_id=1,type=all,bucket=actions=drop"
        echo >>expout3 "ONFT_REQUESTFORWARD (OF1.3): reason=group_mod
 ADD group_id=1,type=all,bucket=actions=drop"
    fi

    # OFPGC_MODIFY
    # OFPT_GROUP_MOD (OF1.3) (xid=0x2):
    # MOD group_id=1,type=select,bucket=weight:0,actions=drop
    ovs-appctl -t `pwd`/c2 ofctl/send "040f0020000000020001010000000001 00100000 ffffffffffffffff 00000000"
    if test X"$1" = X"OFPGC_MODIFY"; then shift;
        echo >>expout2 "send: OFPT_GROUP_MOD (OF1.3):
 MOD group_id=1,type=select,bucket=weight:0,actions=drop"
        echo >>expout1 "ONFT_REQUESTFORWARD (OF1.3): reason=group_mod
 MOD group_id=1,type=select,bucket=weight:0,actions=drop"
        echo >>expout3 "ONFT_REQUESTFORWARD (OF1.3): reason=group_mod
 MOD group_id=1,type=select,bucket=weight:0,actions=drop"
    fi

    ovs-appctl -t `pwd`/c1 ofctl/barrier
    echo >>expout1 "OFPT_BARRIER_REPLY (OF1.3):"
    ovs-appctl -t `pwd`/c2 ofctl/barrier
    echo >>expout2 "OFPT_BARRIER_REPLY (OF1.3):"
    ovs-appctl -t `pwd`/c3 ofctl/barrier
    echo >>expout3 "OFPT_BARRIER_REPLY (OF1.3):"

    # Check output.
    for i in 1 3; do
        cp expout$i expout
        AT_CHECK(
      [[sed '
s/ (xid=0x[0-9a-fA-F]*)//'< monitor$i.log]],
      [0], [expout])
    done
}

# controller 1: Become secondary
# OFPT_ROLE_REQUEST (OF1.3) (xid=0x3): role=secondary
ovs-appctl -t `pwd`/c1 ofctl/send 041800180000000300000003000000008000000000000002

# controller 2: Become primary
# OFPT_ROLE_REQUEST (OF1.3) (xid=0x3): role=primary
ovs-appctl -t `pwd`/c2 ofctl/send 041800180000000300000002000000008000000000000003

# controller 1: Become secondary
# OFPT_ROLE_REQUEST (OF1.3) (xid=0x3): role=secondary
ovs-appctl -t `pwd`/c3 ofctl/send 041800180000000300000003000000008000000000000004

# controller 1: Enabled requestforward using OFPRAW_NXT_SET_ASYNC_CONFIG2 (necessary for OF1.3)
ovs-appctl -t `pwd`/c1 ofctl/send 0404003000000002000023200000001b00000008000000050002000800000002000400080000001a000a000800000003

# controller 2: Enabled requestforward using OFPRAW_NXT_SET_ASYNC_CONFIG2 (necessary for OF1.3)
ovs-appctl -t `pwd`/c2 ofctl/send 0404003000000002000023200000001b000100080000000200030008000000050005000800000005000b000800000003

# controller 1: Enabled requestforward using OFPRAW_NXT_SET_ASYNC_CONFIG2 (necessary for OF1.3)
ovs-appctl -t `pwd`/c3 ofctl/send 0404003000000002000023200000001b00000008000000050002000800000002000400080000001a000a000800000003
check_async 1 OFPGC_ADD OFPGC_MODIFY

OVS_VSWITCHD_STOP
AT_CLEANUP



dnl This test checks that OFPT_PACKET_OUT accepts both OFPP_NONE (as
dnl specified by OpenFlow 1.0) and OFPP_CONTROLLER (used by some
dnl controllers despite the spec) as meaning a packet that was generated
dnl by the controller.
AT_SETUP([ofproto - packet-out from controller (OpenFlow 1.0)])
OVS_VSWITCHD_START
add_of_ports br0 1

# Start a monitor listening for packet-ins.
AT_CHECK([ovs-ofctl -P standard monitor br0 --detach --no-chdir --pidfile])
ovs-appctl -t ovs-ofctl ofctl/send 0109000c0123456700000080
ovs-appctl -t ovs-ofctl ofctl/barrier
ovs-appctl -t ovs-ofctl ofctl/set-output-file monitor.log
AT_CAPTURE_FILE([monitor.log])

# Send some packet-outs with OFPP_NONE and OFPP_CONTROLLER (65533) as in_port.
AT_CHECK([ovs-ofctl packet-out br0 "in_port=none packet=0001020304050010203040501234 actions=controller,1"])
AT_CHECK([ovs-ofctl packet-out br0 "in_port=controller packet=0001020304050010203040505678 actions=controller,1"])

# Stop the monitor and check its output.
ovs-appctl -t ovs-ofctl ofctl/barrier
OVS_APP_EXIT_AND_WAIT([ovs-ofctl])

ovs-ofctl dump-ports br0

AT_CHECK([sed 's/ (xid=0x[[0-9a-fA-F]]*)//' monitor.log], [0], [dnl
OFPT_PACKET_IN: total_len=14 in_port=ANY (via action) data_len=14 (unbuffered)
vlan_tci=0x0000,dl_src=00:10:20:30:40:50,dl_dst=00:01:02:03:04:05,dl_type=0x1234
OFPT_PACKET_IN: total_len=14 in_port=CONTROLLER (via action) data_len=14 (unbuffered)
vlan_tci=0x0000,dl_src=00:10:20:30:40:50,dl_dst=00:01:02:03:04:05,dl_type=0x5678
OFPT_BARRIER_REPLY:
])

OVS_VSWITCHD_STOP
AT_CLEANUP

dnl This test checks that OFPT_PACKET_OUT accepts both OFPP_NONE (as
dnl specified by OpenFlow 1.2) and OFPP_CONTROLLER (used by some
dnl controllers despite the spec) as meaning a packet that was generated
dnl by the controller.
AT_SETUP([ofproto - packet-out from controller (OpenFlow 1.2)])
OVS_VSWITCHD_START

# Start a monitor listening for packet-ins.
AT_CHECK([ovs-ofctl -O OpenFlow12 -P standard monitor br0 --detach --no-chdir --pidfile])
ovs-appctl -t ovs-ofctl ofctl/send 0309000c0123456700000080
ovs-appctl -t ovs-ofctl ofctl/barrier
ovs-appctl -t ovs-ofctl ofctl/set-output-file monitor.log
AT_CAPTURE_FILE([monitor.log])

# Send some packet-outs with OFPP_NONE and OFPP_CONTROLLER (65533) as in_port.
AT_CHECK([ovs-ofctl -O OpenFlow12 packet-out br0 none controller '0001020304050010203040501234'])
AT_CHECK([ovs-ofctl -O OpenFlow12 packet-out br0 4294967293 controller '0001020304050010203040505678'])

# Stop the monitor and check its output.
ovs-appctl -t ovs-ofctl ofctl/barrier
OVS_APP_EXIT_AND_WAIT([ovs-ofctl])

AT_CHECK([sed 's/ (xid=0x[[0-9a-fA-F]]*)//' monitor.log], [0], [dnl
OFPT_PACKET_IN (OF1.2): total_len=14 in_port=ANY (via action) data_len=14 (unbuffered)
vlan_tci=0x0000,dl_src=00:10:20:30:40:50,dl_dst=00:01:02:03:04:05,dl_type=0x1234
OFPT_PACKET_IN (OF1.2): total_len=14 in_port=CONTROLLER (via action) data_len=14 (unbuffered)
vlan_tci=0x0000,dl_src=00:10:20:30:40:50,dl_dst=00:01:02:03:04:05,dl_type=0x5678
OFPT_BARRIER_REPLY (OF1.2):
])

OVS_VSWITCHD_STOP
AT_CLEANUP

dnl This test checks that OFPT_PACKET_OUT accepts both OFPP_NONE (as
dnl specified by OpenFlow 1.1) and OFPP_CONTROLLER (used by some
dnl controllers despite the spec) as meaning a packet that was generated
dnl by the controller.
AT_SETUP([ofproto - packet-out from controller (OpenFlow 1.1)])
OVS_VSWITCHD_START

# Start a monitor listening for packet-ins.
AT_CHECK([ovs-ofctl -O OpenFlow11 -P standard monitor br0 --detach --no-chdir --pidfile])
ovs-appctl -t ovs-ofctl ofctl/send 0209000c0123456700000080
ovs-appctl -t ovs-ofctl ofctl/barrier
ovs-appctl -t ovs-ofctl ofctl/set-output-file monitor.log
AT_CAPTURE_FILE([monitor.log])

# Send some packet-outs with OFPP_NONE and OFPP_CONTROLLER as in_port.
AT_CHECK([ovs-appctl -t ovs-ofctl ofctl/packet-out "in_port=none, packet=0001020304050010203040501234 actions=controller"])
AT_CHECK([ovs-appctl -t ovs-ofctl ofctl/packet-out "in_port=controller packet=0001020304050010203040505678 actions=controller"])

# Stop the monitor and check its output.
ovs-appctl -t ovs-ofctl ofctl/barrier
OVS_APP_EXIT_AND_WAIT([ovs-ofctl])

AT_CHECK([sed 's/ (xid=0x[[0-9a-fA-F]]*)//
/PACKET_OUT/d' monitor.log], [0], [dnl
OFPT_PACKET_IN (OF1.1): total_len=14 in_port=ANY (via action) data_len=14 (unbuffered)
vlan_tci=0x0000,dl_src=00:10:20:30:40:50,dl_dst=00:01:02:03:04:05,dl_type=0x1234
OFPT_PACKET_IN (OF1.1): total_len=14 in_port=CONTROLLER (via action) data_len=14 (unbuffered)
vlan_tci=0x0000,dl_src=00:10:20:30:40:50,dl_dst=00:01:02:03:04:05,dl_type=0x5678
OFPT_BARRIER_REPLY (OF1.1):
])

OVS_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([ofproto - packet-out from controller (OpenFlow 1.5)])
OVS_VSWITCHD_START

# Start a monitor listening for packet-ins.
AT_CHECK([ovs-ofctl -O OpenFlow15 -P standard monitor br0 --detach --no-chdir --pidfile])
ovs-appctl -t ovs-ofctl ofctl/send 0609000c0123456700000080
ovs-appctl -t ovs-ofctl ofctl/barrier
ovs-appctl -t ovs-ofctl ofctl/set-output-file monitor.log
AT_CAPTURE_FILE([monitor.log])

# Send some packet-outs with OFPP_NONE and OFPP_CONTROLLER (65533) as in_port.
AT_CHECK([ovs-ofctl -O OpenFlow15 packet-out br0 "in_port=none tun_id=0x11 metadata=0x22 packet=0001020304050010203040501234 actions=controller"])
AT_CHECK([ovs-ofctl -O OpenFlow15 packet-out br0 "in_port=controller tun_id=0x11 metadata=0x33 packet=0001020304050010203040505678 actions=controller"])

# Stop the monitor and check its output.
ovs-appctl -t ovs-ofctl ofctl/barrier
OVS_APP_EXIT_AND_WAIT([ovs-ofctl])

AT_CHECK([sed 's/ (xid=0x[[0-9a-fA-F]]*)//' monitor.log], [0], [dnl
OFPT_PACKET_IN (OF1.5): total_len=14 tun_id=0x11,metadata=0x22,in_port=ANY (via packet_out) data_len=14 (unbuffered)
vlan_tci=0x0000,dl_src=00:10:20:30:40:50,dl_dst=00:01:02:03:04:05,dl_type=0x1234
OFPT_PACKET_IN (OF1.5): total_len=14 tun_id=0x11,metadata=0x33,in_port=CONTROLLER (via packet_out) data_len=14 (unbuffered)
vlan_tci=0x0000,dl_src=00:10:20:30:40:50,dl_dst=00:01:02:03:04:05,dl_type=0x5678
OFPT_BARRIER_REPLY (OF1.5):
])

OVS_VSWITCHD_STOP
AT_CLEANUP

dnl This test checks that metadata and userdata are encoded in NXT_PACKET_IN2.
AT_SETUP([ofproto - packet-out with metadata and userdata (NXT_PACKET_IN2)])
OVS_VSWITCHD_START

# Start a monitor listening for packet-ins.
AT_CHECK([ovs-ofctl -P nxt_packet_in2 monitor br0 --detach --no-chdir --pidfile])
ovs-appctl -t ovs-ofctl ofctl/send 0109000c0123456700000080
ovs-appctl -t ovs-ofctl ofctl/barrier
ovs-appctl -t ovs-ofctl ofctl/set-output-file monitor.log
AT_CAPTURE_FILE([monitor.log])

# Send a packet-out with a load action to set some metadata, and forward to controller
AT_CHECK([ovs-ofctl packet-out br0 "in_port=controller packet=0001020304050010203040501234 actions=load(0xfafafafa5a5a5a5a->OXM_OF_METADATA[[0..63]]),load(0xaa->NXM_NX_PKT_MARK[[]]),controller(userdata=01.02.03.04.05)"])

# Stop the monitor and check its output.
ovs-appctl -t ovs-ofctl ofctl/barrier
OVS_APP_EXIT_AND_WAIT([ovs-ofctl])

AT_CHECK([sed 's/ (xid=0x[[0-9a-fA-F]]*)//' monitor.log], [0], [dnl
NXT_PACKET_IN2: total_len=14 pkt_mark=0xaa,metadata=0xfafafafa5a5a5a5a,in_port=CONTROLLER (via action) data_len=14 (unbuffered)
 userdata=01.02.03.04.05
vlan_tci=0x0000,dl_src=00:10:20:30:40:50,dl_dst=00:01:02:03:04:05,dl_type=0x1234
OFPT_BARRIER_REPLY:
])

OVS_VSWITCHD_STOP
AT_CLEANUP

dnl This test checks that 1.5 packet_out is properly encoded/decoded.
AT_SETUP([ofproto - packet-out with set_field metadata (OpenFlow 1.5)])
OVS_VSWITCHD_START

# Start a monitor listening for packet-ins.
AT_CHECK([ovs-ofctl -P standard -O OpenFlow13 monitor br0 --detach --no-chdir --pidfile])
ovs-appctl -t ovs-ofctl ofctl/send 0409000c0123456700000080
ovs-appctl -t ovs-ofctl ofctl/barrier
ovs-appctl -t ovs-ofctl ofctl/set-output-file monitor.log
AT_CAPTURE_FILE([monitor.log])

# Send a packet-out with a couple of set-field action to set some metadata, and forward to controller
AT_CHECK([ovs-ofctl -O OpenFlow15 packet-out br0 CONTROLLER 'set_field:0xfafafafa5a5a5a5a->metadata, controller' '0001020304050010203040501234'])

# Stop the monitor and check its output.
ovs-appctl -t ovs-ofctl ofctl/barrier
ovs-appctl -t ovs-ofctl exit

AT_CHECK([sed 's/ (xid=0x[[0-9a-fA-F]]*)//' monitor.log], [0], [dnl
OFPT_PACKET_IN (OF1.3): total_len=14 metadata=0xfafafafa5a5a5a5a,in_port=CONTROLLER (via action) data_len=14 (unbuffered)
vlan_tci=0x0000,dl_src=00:10:20:30:40:50,dl_dst=00:01:02:03:04:05,dl_type=0x1234
OFPT_BARRIER_REPLY (OF1.3):
])

OVS_VSWITCHD_STOP
AT_CLEANUP

dnl This test checks that packet_type PT_ETH is properly encoded/decoded in 1.5 packet_out.
AT_SETUP([ofproto - packet-out with set_field metadata with packet_type PT_ETH (OpenFlow 1.5)])
OVS_VSWITCHD_START

# Start a monitor listening for packet-ins.
AT_CHECK([ovs-ofctl -P standard -O OpenFlow13 monitor br0 --detach --no-chdir --pidfile])
ovs-appctl -t ovs-ofctl ofctl/send 0409000c0123456700000080
ovs-appctl -t ovs-ofctl ofctl/barrier
ovs-appctl -t ovs-ofctl ofctl/set-output-file monitor.log
AT_CAPTURE_FILE([monitor.log])

# Send a packet-out with a couple of set-field action to set some metadata, and forward to controller
AT_CHECK([ovs-ofctl -O OpenFlow15 packet-out br0 "in_port=controller packet=0001020304050010203040501234 packet_type(0,0x0) actions=set_field:0xfafafafa5a5a5a5a->metadata,controller"])

# Stop the monitor and check its output.
ovs-appctl -t ovs-ofctl ofctl/barrier
ovs-appctl -t ovs-ofctl exit

AT_CHECK([sed 's/ (xid=0x[[0-9a-fA-F]]*)//' monitor.log], [0], [dnl
OFPT_PACKET_IN (OF1.3): total_len=14 metadata=0xfafafafa5a5a5a5a,in_port=CONTROLLER (via action) data_len=14 (unbuffered)
vlan_tci=0x0000,dl_src=00:10:20:30:40:50,dl_dst=00:01:02:03:04:05,dl_type=0x1234
OFPT_BARRIER_REPLY (OF1.3):
])

OVS_VSWITCHD_STOP
AT_CLEANUP

dnl This test checks that packet_type PT_IPV4 is properly encoded/decoded in 1.5 packet_out.
AT_SETUP([ofproto - packet-out with set_field metadata with packet_type PT_IPV4 on PTAP bridge (OpenFlow 1.5)])
OVS_VSWITCHD_START

# Start a monitor listening for packet-ins.
AT_CHECK([ovs-ofctl -P standard -O OpenFlow13 monitor br0 --detach --no-chdir --pidfile])
ovs-appctl -t ovs-ofctl ofctl/send 0409000c0123456700000080
ovs-appctl -t ovs-ofctl ofctl/barrier
ovs-appctl -t ovs-ofctl ofctl/set-output-file monitor.log
AT_CAPTURE_FILE([monitor.log])

# Send a packet-out with a couple of set-field action to set some metadata, and forward to controller
AT_CHECK([ovs-ofctl -O OpenFlow15 packet-out br0 "in_port=controller packet=4500002012344000ff1155670a0000140a00001e006400c8000cea78ffffffff packet_type(1,0x800) actions=set_field:0xfafafafa5a5a5a5a->metadata,controller"])

# Stop the monitor and check its output.
ovs-appctl -t ovs-ofctl ofctl/barrier
ovs-appctl -t ovs-ofctl exit

AT_CHECK([sed 's/ (xid=0x[[0-9a-fA-F]]*)//' monitor.log], [0], [dnl
OFPT_PACKET_IN (OF1.3): total_len=32 packet_type=(1,0x800),metadata=0xfafafafa5a5a5a5a,in_port=CONTROLLER (via action) data_len=32 (unbuffered)
packet_type=(1,0x800),nw_src=10.0.0.20,nw_dst=10.0.0.30,nw_proto=17,nw_tos=0,nw_ecn=0,nw_ttl=255,nw_frag=no,tp_src=100,tp_dst=200 udp_csum:ea78
OFPT_BARRIER_REPLY (OF1.3):
])

OVS_VSWITCHD_STOP
AT_CLEANUP

dnl This test checks that metadata is encoded in packet_in structures,
dnl supported by NXAST.
AT_SETUP([ofproto - packet-out with metadata (NXM)])
OVS_VSWITCHD_START

# Start a monitor listening for packet-ins.
AT_CHECK([ovs-ofctl -P nxt_packet_in monitor br0 --detach --no-chdir --pidfile])
ovs-appctl -t ovs-ofctl ofctl/send 0109000c0123456700000080
ovs-appctl -t ovs-ofctl ofctl/barrier
ovs-appctl -t ovs-ofctl ofctl/set-output-file monitor.log
AT_CAPTURE_FILE([monitor.log])

# Send a packet-out with a load action to set some metadata, and forward to controller
AT_CHECK([ovs-ofctl packet-out br0 "in_port=controller packet=0001020304050010203040501234 actions=load(0xfafafafa5a5a5a5a->OXM_OF_METADATA[[0..63]]),load(0xaa->NXM_NX_PKT_MARK[[]]),controller"])

# Stop the monitor and check its output.
ovs-appctl -t ovs-ofctl ofctl/barrier
OVS_APP_EXIT_AND_WAIT([ovs-ofctl])

AT_CHECK([sed 's/ (xid=0x[[0-9a-fA-F]]*)//' monitor.log], [0], [dnl
NXT_PACKET_IN: total_len=14 pkt_mark=0xaa,metadata=0xfafafafa5a5a5a5a,in_port=CONTROLLER (via action) data_len=14 (unbuffered)
vlan_tci=0x0000,dl_src=00:10:20:30:40:50,dl_dst=00:01:02:03:04:05,dl_type=0x1234
OFPT_BARRIER_REPLY:
])

OVS_VSWITCHD_STOP
AT_CLEANUP

dnl This test checks that metadata is encoded in packet_in structures,
dnl supported by NXAST.
AT_SETUP([ofproto - packet-out with metadata (OpenFlow 1.2)])
OVS_VSWITCHD_START

# Start a monitor listening for packet-ins.
AT_CHECK([ovs-ofctl -O OpenFlow12 -P standard monitor br0 --detach --no-chdir --pidfile])
ovs-appctl -t ovs-ofctl ofctl/send 0309000c0123456700000080
ovs-appctl -t ovs-ofctl ofctl/barrier
ovs-appctl -t ovs-ofctl ofctl/set-output-file monitor.log
AT_CAPTURE_FILE([monitor.log])

# Send a packet-out with a set-field action to set some metadata, and forward to controller
AT_CHECK([ovs-ofctl -O OpenFlow12 packet-out br0 none 'set_field:0xfafafafa5a5a5a5a->metadata, controller' '0001020304050010203040501234'])

# Stop the monitor and check its output.
ovs-appctl -t ovs-ofctl ofctl/barrier
OVS_APP_EXIT_AND_WAIT([ovs-ofctl])

AT_CHECK([sed 's/ (xid=0x[[0-9a-fA-F]]*)//' monitor.log], [0], [dnl
OFPT_PACKET_IN (OF1.2): total_len=14 metadata=0xfafafafa5a5a5a5a,in_port=ANY (via action) data_len=14 (unbuffered)
vlan_tci=0x0000,dl_src=00:10:20:30:40:50,dl_dst=00:01:02:03:04:05,dl_type=0x1234
OFPT_BARRIER_REPLY (OF1.2):
])

OVS_VSWITCHD_STOP
AT_CLEANUP

dnl This test checks that metadata is encoded in packet_in structures,
dnl supported by NXAST.
AT_SETUP([ofproto - packet-out with metadata and dual set_field (OpenFlow 1.3)])
OVS_VSWITCHD_START

# Start a monitor listening for packet-ins.
AT_CHECK([ovs-ofctl -O OpenFlow13 -P standard monitor br0 --detach --no-chdir --pidfile])
ovs-appctl -t ovs-ofctl ofctl/send 0409000c0123456700000080
ovs-appctl -t ovs-ofctl ofctl/barrier
ovs-appctl -t ovs-ofctl ofctl/set-output-file monitor.log
AT_CAPTURE_FILE([monitor.log])

# Send a packet-out with a couple of set-field action to set some metadata, and forward to controller
AT_CHECK([ovs-ofctl -O OpenFlow13 packet-out br0 none 'set_field:0xfafafafa5a5a5a5a->metadata, set_field:0x6b->metadata, controller' '0001020304050010203040501234'])

# Stop the monitor and check its output.
ovs-appctl -t ovs-ofctl ofctl/barrier
OVS_APP_EXIT_AND_WAIT([ovs-ofctl])

AT_CHECK([sed 's/ (xid=0x[[0-9a-fA-F]]*)//' monitor.log], [0], [dnl
OFPT_PACKET_IN (OF1.3): total_len=14 metadata=0x6b,in_port=ANY (via action) data_len=14 (unbuffered)
vlan_tci=0x0000,dl_src=00:10:20:30:40:50,dl_dst=00:01:02:03:04:05,dl_type=0x1234
OFPT_BARRIER_REPLY (OF1.3):
])

OVS_VSWITCHD_STOP
AT_CLEANUP

dnl This test checks that tunnel metadata is encoded in packet_in structures.
AT_SETUP([ofproto - packet-out with tunnel metadata (OpenFlow 1.2)])
OVS_VSWITCHD_START

# Start a monitor listening for packet-ins.
AT_CHECK([ovs-ofctl -O OpenFlow12 -P standard monitor br0 --detach --no-chdir --pidfile])
ovs-appctl -t ovs-ofctl ofctl/send 0309000c0123456700000080
ovs-appctl -t ovs-ofctl ofctl/barrier
ovs-appctl -t ovs-ofctl ofctl/set-output-file monitor.log
AT_CAPTURE_FILE([monitor.log])

# Send a packet-out with set field actions to set some tunnel metadata, and forward to controller
AT_CHECK([ovs-ofctl -O OpenFlow12 packet-out br0 none 'set_field:127.0.0.1->tun_src,set_field:0x01020304->tun_id,set_field:192.168.0.1->tun_dst, controller' '0001020304050010203040501234'])

# Stop the monitor and check its output.
ovs-appctl -t ovs-ofctl ofctl/barrier
OVS_APP_EXIT_AND_WAIT([ovs-ofctl])

AT_CHECK([sed 's/ (xid=0x[[0-9a-fA-F]]*)//' monitor.log], [0], [dnl
OFPT_PACKET_IN (OF1.2): total_len=14 tun_id=0x1020304,tun_src=127.0.0.1,tun_dst=192.168.0.1,in_port=ANY (via action) data_len=14 (unbuffered)
vlan_tci=0x0000,dl_src=00:10:20:30:40:50,dl_dst=00:01:02:03:04:05,dl_type=0x1234
OFPT_BARRIER_REPLY (OF1.2):
])

OVS_VSWITCHD_STOP
AT_CLEANUP

m4_divert_push([PREPARE_TESTS])
# Sorts groups of lines that start with a space, without moving them
# past the nearest line that does not start with a space.
[
multiline_sort () {
    $PYTHON3 -c '
import sys

buffer = []
while True:
    line = sys.stdin.readline()
    if not line:
        break
    if line.startswith(" "):
        buffer.append(line)
    else:
        sys.stdout.write("".join(sorted(buffer)))
        sys.stdout.write(line)
        buffer = []
sys.stdout.write("".join(sorted(buffer)))
'
}
]
m4_divert_pop([PREPARE_TESTS])

dnl Flow monitoring tests verified across all supported protocols
dnl CHECK_FLOW_MONITORING(label, option, format)
m4_define([CHECK_FLOW_MONITORING], [
AT_SETUP([ofproto - flow monitoring - (OpenFlow $1)])
AT_KEYWORDS([monitor])
OVS_VSWITCHD_START

# Get packet data to used as part of ofctl/send operation before doing anything else
send_buf=$(ovs-ofctl -O $2 del-flows br0 table=0 -mmmmmm |  sed 's/0x/0/' | sed -E 's/^(.{8})(.{8})/\112345678/' )

ovs-ofctl add-flow br0 in_port=0,dl_vlan=123,actions=output:1

# Start a monitor watching the flow table and check the initial reply.
ovs-ofctl -O $2 monitor br0 watch: --detach --no-chdir --pidfile >monitor.log 2>&1
AT_CAPTURE_FILE([monitor.log])
ovs-appctl -t ovs-ofctl ofctl/barrier

# For OF(1.4+), replace INITIAL to ADDED
sed -i'.raw' -e 's|event=INITIAL|event=ADDED|' monitor.log
AT_CHECK([sed 's/ (xid=0x[[1-9a-fA-F]][[0-9a-fA-F]]*)//' monitor.log], [0],
  [$4 reply$3:
 event=ADDED table=0 cookie=0 in_port=0,dl_vlan=123 actions=output:1
OFPT_BARRIER_REPLY$3:
])

# Add, delete, and modify some flows and check the updates.
ovs-appctl -t ovs-ofctl ofctl/set-output-file monitor.log
ovs-ofctl add-flow br0 in_port=0,dl_vlan=124,actions=output:2
ovs-ofctl add-flow br0 in_port=0,dl_vlan=123,actions=output:5
ovs-ofctl add-flow br0 in_port=0,dl_vlan=123,dl_vlan_pcp=0,actions=output:6
ovs-ofctl add-flow br0 in_port=0,dl_vlan=123,dl_vlan_pcp=1,actions=output:7
ovs-ofctl add-flow br0 in_port=0,dl_vlan=123,actions=output:8
ovs-ofctl add-flow br0 in_port=0,dl_vlan=65535,dl_vlan_pcp=0,actions=output:9
ovs-ofctl add-flow br0 in_port=0,dl_vlan=65535,dl_vlan_pcp=1,actions=output:10
ovs-ofctl add-flow br0 in_port=0,dl_vlan=65535,dl_vlan_pcp=3,actions=output:11
ovs-ofctl add-flow br0 in_port=0,dl_vlan=8191,dl_vlan_pcp=0,actions=output:12
ovs-ofctl add-flow br0 in_port=0,dl_vlan=8191,dl_vlan_pcp=1,actions=output:13
ovs-ofctl add-flow br0 in_port=0,dl_vlan=8191,actions=output:14
ovs-ofctl add-flow br0 in_port=0,dl_vlan=0,dl_vlan_pcp=0,actions=output:15
ovs-ofctl add-flow br0 in_port=0,dl_vlan=0,dl_vlan_pcp=1,actions=output:16
ovs-ofctl add-flow br0 in_port=0,dl_vlan=0,actions=output:17
ovs-ofctl add-flow br0 in_port=0,dl_vlan=0,dl_vlan_pcp=0,actions=output:18
ovs-ofctl add-flow br0 in_port=0,dl_vlan=0,dl_vlan_pcp=1,actions=output:19
ovs-ofctl add-flow br0 in_port=0,dl_vlan=0,actions=output:20
ovs-ofctl add-flow br0 in_port=0,dl_vlan_pcp=0,actions=output:21
ovs-ofctl add-flow br0 in_port=0,dl_vlan_pcp=1,actions=output:22
ovs-ofctl add-flow br0 in_port=0,actions=output:23
ovs-ofctl mod-flows br0 dl_vlan=123,actions=output:3
ovs-ofctl mod-flows br0 cookie=5,dl_vlan=123,actions=output:3
ovs-ofctl del-flows br0 dl_vlan=123
ovs-ofctl del-flows br0
ovs-appctl -t ovs-ofctl ofctl/barrier

# For OF(1.4+), replace INITIAL to ADDED
sed -i'.raw' -e 's|event=INITIAL|event=ADDED|' monitor.log
AT_CHECK([sed 's/ (xid=0x[[1-9a-fA-F]][[0-9a-fA-F]]*)//' monitor.log | multiline_sort], [0],
[$4 reply$3 (xid=0x0):
 event=ADDED table=0 cookie=0 in_port=0,dl_vlan=124 actions=output:2
$4 reply$3 (xid=0x0):
 event=ADDED table=0 cookie=0 in_port=0,dl_vlan=123 actions=output:5
$4 reply$3 (xid=0x0):
 event=ADDED table=0 cookie=0 in_port=0,dl_vlan=123,dl_vlan_pcp=0 actions=output:6
$4 reply$3 (xid=0x0):
 event=ADDED table=0 cookie=0 in_port=0,dl_vlan=123,dl_vlan_pcp=1 actions=output:7
$4 reply$3 (xid=0x0):
 event=ADDED table=0 cookie=0 in_port=0,dl_vlan=123 actions=output:8
$4 reply$3 (xid=0x0):
 event=ADDED table=0 cookie=0 in_port=0,dl_vlan=0,dl_vlan_pcp=0 actions=output:9
$4 reply$3 (xid=0x0):
 event=ADDED table=0 cookie=0 in_port=0,dl_vlan=0,dl_vlan_pcp=1 actions=output:10
$4 reply$3 (xid=0x0):
 event=ADDED table=0 cookie=0 in_port=0,dl_vlan=0,dl_vlan_pcp=3 actions=output:11
$4 reply$3 (xid=0x0):
 event=ADDED table=0 cookie=0 in_port=0,dl_vlan=4095,dl_vlan_pcp=0 actions=output:12
$4 reply$3 (xid=0x0):
 event=ADDED table=0 cookie=0 in_port=0,dl_vlan=4095,dl_vlan_pcp=1 actions=output:13
$4 reply$3 (xid=0x0):
 event=ADDED table=0 cookie=0 in_port=0,dl_vlan=4095 actions=output:14
$4 reply$3 (xid=0x0):
 event=ADDED table=0 cookie=0 in_port=0,dl_vlan=0,dl_vlan_pcp=0 actions=output:15
$4 reply$3 (xid=0x0):
 event=ADDED table=0 cookie=0 in_port=0,dl_vlan=0,dl_vlan_pcp=1 actions=output:16
$4 reply$3 (xid=0x0):
 event=ADDED table=0 cookie=0 in_port=0,dl_vlan=0 actions=output:17
$4 reply$3 (xid=0x0):
 event=ADDED table=0 cookie=0 in_port=0,dl_vlan=0,dl_vlan_pcp=0 actions=output:18
$4 reply$3 (xid=0x0):
 event=ADDED table=0 cookie=0 in_port=0,dl_vlan=0,dl_vlan_pcp=1 actions=output:19
$4 reply$3 (xid=0x0):
 event=ADDED table=0 cookie=0 in_port=0,dl_vlan=0 actions=output:20
$4 reply$3 (xid=0x0):
 event=ADDED table=0 cookie=0 in_port=0,dl_vlan_pcp=0 actions=output:21
$4 reply$3 (xid=0x0):
 event=ADDED table=0 cookie=0 in_port=0,dl_vlan_pcp=1 actions=output:22
$4 reply$3 (xid=0x0):
 event=ADDED table=0 cookie=0 in_port=0 actions=output:23
$4 reply$3 (xid=0x0):
 event=MODIFIED table=0 cookie=0 in_port=0,dl_vlan=123 actions=output:3
 event=MODIFIED table=0 cookie=0 in_port=0,dl_vlan=123,dl_vlan_pcp=0 actions=output:3
 event=MODIFIED table=0 cookie=0 in_port=0,dl_vlan=123,dl_vlan_pcp=1 actions=output:3
$4 reply$3 (xid=0x0):
 event=MODIFIED table=0 cookie=0x5 in_port=0,dl_vlan=123 actions=output:3
 event=MODIFIED table=0 cookie=0x5 in_port=0,dl_vlan=123,dl_vlan_pcp=0 actions=output:3
 event=MODIFIED table=0 cookie=0x5 in_port=0,dl_vlan=123,dl_vlan_pcp=1 actions=output:3
$4 reply$3 (xid=0x0):
 event=DELETED reason=delete table=0 cookie=0x5 in_port=0,dl_vlan=123 actions=output:3
 event=DELETED reason=delete table=0 cookie=0x5 in_port=0,dl_vlan=123,dl_vlan_pcp=0 actions=output:3
 event=DELETED reason=delete table=0 cookie=0x5 in_port=0,dl_vlan=123,dl_vlan_pcp=1 actions=output:3
$4 reply$3 (xid=0x0):
 event=DELETED reason=delete table=0 cookie=0 in_port=0 actions=output:23
 event=DELETED reason=delete table=0 cookie=0 in_port=0,dl_vlan=0 actions=output:20
 event=DELETED reason=delete table=0 cookie=0 in_port=0,dl_vlan=0,dl_vlan_pcp=0 actions=output:18
 event=DELETED reason=delete table=0 cookie=0 in_port=0,dl_vlan=0,dl_vlan_pcp=1 actions=output:19
 event=DELETED reason=delete table=0 cookie=0 in_port=0,dl_vlan=0,dl_vlan_pcp=3 actions=output:11
 event=DELETED reason=delete table=0 cookie=0 in_port=0,dl_vlan=124 actions=output:2
 event=DELETED reason=delete table=0 cookie=0 in_port=0,dl_vlan=4095 actions=output:14
 event=DELETED reason=delete table=0 cookie=0 in_port=0,dl_vlan=4095,dl_vlan_pcp=0 actions=output:12
 event=DELETED reason=delete table=0 cookie=0 in_port=0,dl_vlan=4095,dl_vlan_pcp=1 actions=output:13
 event=DELETED reason=delete table=0 cookie=0 in_port=0,dl_vlan_pcp=0 actions=output:21
 event=DELETED reason=delete table=0 cookie=0 in_port=0,dl_vlan_pcp=1 actions=output:22
OFPT_BARRIER_REPLY$3:
])

# Check that our own changes are reported as full updates.
ovs-appctl -t ovs-ofctl ofctl/set-output-file monitor.log
ovs-ofctl add-flow br0 in_port=1,actions=output:2
ovs-ofctl add-flow br0 in_port=2,actions=output:1
ovs-appctl -t ovs-ofctl ofctl/barrier
ovs-appctl -t ovs-ofctl ofctl/send $send_buf
ovs-appctl -t ovs-ofctl ofctl/barrier
AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip], [0], [NXST_FLOW reply:
])
AT_CHECK([sed 's/ (xid=0x[[1-9a-fA-F]][[0-9a-fA-F]]*)//' monitor.log | multiline_sort], [0],
[$4 reply$3 (xid=0x0):
 event=ADDED table=0 cookie=0 in_port=1 actions=output:2
$4 reply$3 (xid=0x0):
 event=ADDED table=0 cookie=0 in_port=2 actions=output:1
OFPT_BARRIER_REPLY$3:
send: OFPT_FLOW_MOD$3: DEL actions=drop
$4 reply$3 (xid=0x0):
 event=DELETED reason=delete table=0 cookie=0 in_port=1 actions=output:2
 event=DELETED reason=delete table=0 cookie=0 in_port=2 actions=output:1
OFPT_BARRIER_REPLY$3:
])

OVS_APP_EXIT_AND_WAIT([ovs-ofctl])
OVS_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([ofproto - flow monitoring with !own - (OpenFlow $1)])
AT_KEYWORDS([monitor])
OVS_VSWITCHD_START

# Get packet data to used as part of ofctl/send operation before doing anything else
send_buf=$(ovs-ofctl -O $2 del-flows br0 table=0 -mmmmmm |  sed 's/0x/0/' | sed -E 's/^(.{8})(.{8})/\112345678/' )

ovs-ofctl add-flow br0 in_port=0,dl_vlan=123,actions=output:1

# Start a monitor watching the flow table and check the initial reply.
ovs-ofctl -O $2 monitor br0 watch:\!own --detach --no-chdir --pidfile >monitor.log 2>&1
AT_CAPTURE_FILE([monitor.log])
ovs-appctl -t ovs-ofctl ofctl/barrier

# For OF(1.4+), replace INITIAL to ADDED
sed -i'.raw' -e 's|event=INITIAL|event=ADDED|' monitor.log
AT_CHECK([sed 's/ (xid=0x[[1-9a-fA-F]][[0-9a-fA-F]]*)//' monitor.log], [0],
  [$4 reply$3:
 event=ADDED table=0 cookie=0 in_port=0,dl_vlan=123 actions=output:1
OFPT_BARRIER_REPLY$3:
])

# Check that our own changes are reported as abbreviations.
ovs-appctl -t ovs-ofctl ofctl/set-output-file monitor.log
ovs-ofctl add-flow br0 in_port=1,actions=output:2
ovs-ofctl add-flow br0 in_port=2,actions=output:1
ovs-appctl -t ovs-ofctl ofctl/barrier
ovs-appctl -t ovs-ofctl ofctl/send $send_buf
ovs-appctl -t ovs-ofctl ofctl/barrier
AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip], [0], [NXST_FLOW reply:
])

# For OF(1.4+), replace INITIAL to ADDED
sed -i'.raw' -e 's|event=INITIAL|event=ADDED|' monitor.log
AT_CHECK([sed 's/ (xid=0x[[1-9a-fA-F]][[0-9a-fA-F]]*)//' monitor.log], [0],
[$4 reply$3 (xid=0x0):
 event=ADDED table=0 cookie=0 in_port=1 actions=output:2
$4 reply$3 (xid=0x0):
 event=ADDED table=0 cookie=0 in_port=2 actions=output:1
OFPT_BARRIER_REPLY$3:
send: OFPT_FLOW_MOD$3: DEL actions=drop
$4 reply$3 (xid=0x0):
 event=ABBREV xid=0x12345678
OFPT_BARRIER_REPLY$3:
])

OVS_APP_EXIT_AND_WAIT([ovs-ofctl])
OVS_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([ofproto - flow monitoring with out_port - (OpenFlow $1)])
AT_KEYWORDS([monitor])
OVS_VSWITCHD_START

ovs-ofctl add-flow br0 in_port=0,dl_vlan=121,actions=output:1
ovs-ofctl add-flow br0 in_port=0,dl_vlan=122,actions=output:1
ovs-ofctl add-flow br0 in_port=0,dl_vlan=123,actions=output:2

# Start a monitor watching the flow table and check the initial reply.
ovs-ofctl -O $2 monitor br0 watch:out_port=2 --detach --no-chdir --pidfile >monitor.log 2>&1
AT_CAPTURE_FILE([monitor.log])
ovs-appctl -t ovs-ofctl ofctl/barrier

# For OF(1.4+), replace INITIAL to ADDED
sed -i'.raw' -e 's|event=INITIAL|event=ADDED|' monitor.log
AT_CHECK([sed 's/ (xid=0x[[1-9a-fA-F]][[0-9a-fA-F]]*)//' monitor.log], [0],
  [$4 reply$3:
 event=ADDED table=0 cookie=0 in_port=0,dl_vlan=123 actions=output:2
OFPT_BARRIER_REPLY$3:
])

ovs-appctl -t ovs-ofctl ofctl/set-output-file monitor.log

# Add, modify flows and check the updates.
ovs-ofctl mod-flows br0 dl_vlan=121,actions=drop
ovs-ofctl mod-flows br0 dl_vlan=122,actions=output:1,output:2
ovs-appctl -t ovs-ofctl ofctl/barrier

ovs-ofctl mod-flows br0 dl_vlan=123,actions=output:1,output:2
ovs-appctl -t ovs-ofctl ofctl/barrier

ovs-ofctl mod-flows br0 dl_vlan=122,actions=output:1
ovs-appctl -t ovs-ofctl ofctl/barrier
ovs-ofctl mod-flows br0 dl_vlan=123,actions=output:2
ovs-appctl -t ovs-ofctl ofctl/barrier

# For OF(1.4+), replace INITIAL to ADDED
sed -i'.raw' -e 's|event=INITIAL|event=ADDED|' monitor.log
AT_CHECK([sed 's/ (xid=0x[[1-9a-fA-F]][[0-9a-fA-F]]*)//' monitor.log], [0],
[$4 reply$3 (xid=0x0):
 event=MODIFIED table=0 cookie=0 in_port=0,dl_vlan=122 actions=output:1,output:2
OFPT_BARRIER_REPLY$3:
$4 reply$3 (xid=0x0):
 event=MODIFIED table=0 cookie=0 in_port=0,dl_vlan=123 actions=output:1,output:2
OFPT_BARRIER_REPLY$3:
$4 reply$3 (xid=0x0):
 event=MODIFIED table=0 cookie=0 in_port=0,dl_vlan=122 actions=output:1
OFPT_BARRIER_REPLY$3:
$4 reply$3 (xid=0x0):
 event=MODIFIED table=0 cookie=0 in_port=0,dl_vlan=123 actions=output:2
OFPT_BARRIER_REPLY$3:
])

OVS_APP_EXIT_AND_WAIT([ovs-ofctl])
OVS_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([ofproto - flow monitoring pause and resume - (OpenFlow $1)])
AT_KEYWORDS([monitor])

# The maximum socket receive buffer size is important for this test, which
# tests behavior when the receive buffer overflows.
if test -e /proc/sys/net/core/rmem_max; then
    # Linux
    rmem_max=`cat /proc/sys/net/core/rmem_max`
elif rmem_max=`sysctl -n net.inet.tcp.recvbuf_max 2>/dev/null`; then
    : # FreeBSD, NetBSD
else
    # Don't know how to get maximum socket receive buffer on this OS
    AT_SKIP_IF([:])
fi
# Calculate the total amount of queuing: rmem_max in the kernel, 128 kB
# in ofproto sending userspace (see ofmonitor_flush() in connmgr.c).
queue_size=`expr $rmem_max + 128 \* 1024`
echo rmem_max=$rmem_max queue_size=$queue_size

# If there's too much queuing skip the test to avoid timing out.
AT_SKIP_IF([test $rmem_max -gt 1048576])

# Each flow update message takes up at least 48 bytes of space in queues
# and in practice more than that.
n_msgs=`expr $queue_size / 48`
echo n_msgs=$n_msgs

OVS_VSWITCHD_START

# Start a monitor watching the flow table, then make it block.
on_exit 'kill `cat ovs-ofctl.pid`'
ovs-ofctl -O $2 monitor br0 watch: --detach --no-chdir --pidfile >monitor.log 2>&1
AT_CAPTURE_FILE([monitor.log])
ovs-appctl -t ovs-ofctl ofctl/block

# Add $n_msgs flows.
(echo "in_port=2,actions=output:2"
$PYTHON3 -c '
for i in range('$n_msgs'):
    print("cookie=1,reg1=%d,actions=drop" % i)
') > flows.txt
AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
# Check that multipart flow dumps work properly:
AT_CHECK([ovs-ofctl diff-flows br0 flows.txt])
AT_CHECK([ovs-ofctl add-flow br0 in_port=1,cookie=3,actions=drop])
AT_CHECK([ovs-ofctl mod-flows br0 in_port=2,cookie=2,actions=output:2])
AT_CHECK([ovs-ofctl del-flows br0 cookie=1/-1])

ovs-appctl -t ovs-ofctl ofctl/unblock

# Wait for the connection resumed.
# A barrier doesn't work for this purpose.
#    https://www.mail-archive.com/dev@openvswitch.org/msg27013.html
#    https://www.mail-archive.com/dev@openvswitch.org/msg27675.html
OVS_WAIT_UNTIL([grep RESUMED monitor.log])

OVS_APP_EXIT_AND_WAIT([ovs-ofctl])

# Check that the flow monitor reported the same number of flows
# added and deleted, but fewer than we actually added and deleted.
adds=`grep -c 'ADDED.*reg1=' monitor.log`
deletes=`grep -c 'DELETED.*reg1=' monitor.log`
echo adds=$adds deletes=$deletes
AT_CHECK([test $adds -gt 100 && test $adds -lt $n_msgs])
AT_CHECK([test $adds = $deletes])

# Check that the flow monitor reported everything in the expected order:
#
#     event=ADDED table=0 cookie=0x1 reg1=0x22
# ...
#    NXT_FLOW_MONITOR_PAUSED:
# ...
#     event=DELETED reason=delete table=0 cookie=0x1 reg1=0x22
# ...
#     event=ADDED table=0 cookie=0x3 in_port=1
#     event=MODIFIED table=0 cookie=0x2 in_port=2 actions=output:2
#    NXT_FLOW_MONITOR_RESUMED:
#
# except that, between the PAUSED and RESUMED, the order of the ADDED
# and MODIFIED lines lines depends on hash order, that is, it varies
# as we change the hash function or change architecture.  Therefore,
# we use a couple of tests below to accept both orders.

# Rename all version specific strings to a generic one
sed -i'.raw' -e 's|NXT_FLOW_MONITOR|FLOW_MONITOR|' -e 's|ONFT_FLOW_MONITOR|FLOW_MONITOR|' monitor.log
sed -i -z 's|OFPST_FLOW_MONITOR reply$3 (xid=0x0):\n event=PAUSED|FLOW_MONITOR_PAUSED$3:|' monitor.log
sed -i -z 's|OFPST_FLOW_MONITOR reply$3 (xid=0x0):\n event=RESUMED|FLOW_MONITOR_RESUMED$3:|' monitor.log

AT_CHECK([ofctl_strip < monitor.log | sed -n -e '
/reg1=0x22$/p
/cookie=0x[[23]]/p
/FLOW_MONITOR_PAUSED$3:/p
/FLOW_MONITOR_RESUMED$3:/p
' > monitor.log.subset])
AT_CHECK([grep -v MODIFIED monitor.log.subset], [0], [dnl
 event=ADDED table=0 cookie=0x1 reg1=0x22
FLOW_MONITOR_PAUSED$3:
 event=DELETED reason=delete table=0 cookie=0x1 reg1=0x22
 event=ADDED table=0 cookie=0x3 in_port=1
FLOW_MONITOR_RESUMED$3:
])
AT_CHECK([grep -v ADDED monitor.log.subset], [0], [dnl
FLOW_MONITOR_PAUSED$3:
 event=DELETED reason=delete table=0 cookie=0x1 reg1=0x22
 event=MODIFIED table=0 cookie=0x2 in_port=2 actions=output:2
FLOW_MONITOR_RESUMED$3:
])

OVS_VSWITCHD_STOP
AT_CLEANUP

# Test to show flow monitoring support on different OpenFlow protocols
AT_SETUP([ofproto - flow monitoring usable protocols (OpenFlow $1)])
AT_KEYWORDS([monitor])

OVS_VSWITCHD_START

on_exit 'kill `cat ovs-ofctl.pid`'
ovs-ofctl -O $2 monitor br0 watch:udp,udp_dst=8 --detach --no-chdir --pidfile >monitor.log 2>&1
AT_CAPTURE_FILE([monitor.log])

# Wait till reply comes backs with OF Version
OVS_WAIT_UNTIL([grep "$4 reply$3" monitor.log])
ovs-appctl -t ovs-ofctl exit

# Make sure protocol type in messages from vswitchd, matches that of requested protocol
ovs-ofctl -O $2 monitor br0 watch:sctp,sctp_dst=9 --detach --no-chdir --pidfile >monitor.log 2>&1
ovs-ofctl add-flow br0 sctp,sctp_dst=9,action=normal

OVS_WAIT_UNTIL([grep "event=ADDED " monitor.log])
AT_CHECK([sed 's/ (xid=0x[[1-9a-fA-F]][[0-9a-fA-F]]*)//' monitor.log], [0], [dnl
$4 reply$3:
$4 reply$3 (xid=0x0):
 event=ADDED table=0 cookie=0 sctp,tp_dst=9 actions=NORMAL
])
OVS_APP_EXIT_AND_WAIT([ovs-ofctl])
OVS_VSWITCHD_STOP
AT_CLEANUP
])
CHECK_FLOW_MONITORING([1.0], [OpenFlow10], [],         NXST_FLOW_MONITOR)
CHECK_FLOW_MONITORING([1.1], [OpenFlow11], [ (OF1.1)], NXST_FLOW_MONITOR)
CHECK_FLOW_MONITORING([1.2], [OpenFlow12], [ (OF1.2)], NXST_FLOW_MONITOR)
CHECK_FLOW_MONITORING([1.3], [OpenFlow13], [ (OF1.3)], ONFST_FLOW_MONITOR)
CHECK_FLOW_MONITORING([1.4], [OpenFlow14], [ (OF1.4)], OFPST_FLOW_MONITOR)
CHECK_FLOW_MONITORING([1.5], [OpenFlow15], [ (OF1.5)], OFPST_FLOW_MONITOR)

AT_SETUP([ofproto - OpenFlow14 flow monitoring with out_group])
AT_KEYWORDS([monitor])
OVS_VSWITCHD_START

AT_CHECK([ovs-ofctl -O OpenFlow14 add-group br0 group_id=1,type=all,bucket=output:1])
AT_CHECK([ovs-ofctl -O OpenFlow14 add-group br0 group_id=2,type=all,bucket=output:2])

ovs-ofctl -OOpenFlow14 add-flow br0 in_port=0,dl_vlan=121,actions=output:1
ovs-ofctl -OOpenFlow14 add-flow br0 in_port=0,dl_vlan=122,actions=group:1
ovs-ofctl -OOpenFlow14 add-flow br0 in_port=0,dl_vlan=123,actions=group:2

# Start a monitor watching the flow table and check the initial reply.
ovs-ofctl -OOpenFlow14 monitor br0 watch:out_group=2 --detach --no-chdir --pidfile >monitor.log 2>&1
AT_CAPTURE_FILE([monitor.log])
ovs-appctl -t ovs-ofctl ofctl/barrier
AT_CHECK([sed 's/ (xid=0x[[1-9a-fA-F]][[0-9a-fA-F]]*)//' monitor.log], [0],
[OFPST_FLOW_MONITOR reply (OF1.4):
 event=INITIAL table=0 cookie=0 in_port=0,dl_vlan=123 actions=group:2
OFPT_BARRIER_REPLY (OF1.4):
])

ovs-appctl -t ovs-ofctl ofctl/set-output-file monitor.log

# Add, modify flows and check the updates.
ovs-ofctl -OOpenFlow14 mod-flows br0 dl_vlan=121,actions=group:2
ovs-ofctl -OOpenFlow14 mod-flows br0 dl_vlan=122,actions=group:2
ovs-ofctl -OOpenFlow14 mod-flows br0 dl_vlan=123,actions=group:1
ovs-appctl -t ovs-ofctl ofctl/barrier
ovs-ofctl -OOpenFlow14 add-flow br0 in_port=0,dl_vlan=124,actions=group:2

AT_CHECK([sed 's/ (xid=0x[[1-9a-fA-F]][[0-9a-fA-F]]*)//' monitor.log], [0],
[OFPST_FLOW_MONITOR reply (OF1.4) (xid=0x0):
 event=MODIFIED table=0 cookie=0 in_port=0,dl_vlan=121 actions=group:2
OFPST_FLOW_MONITOR reply (OF1.4) (xid=0x0):
 event=MODIFIED table=0 cookie=0 in_port=0,dl_vlan=122 actions=group:2
OFPT_BARRIER_REPLY (OF1.4):
OFPST_FLOW_MONITOR reply (OF1.4) (xid=0x0):
 event=ADDED table=0 cookie=0 in_port=0,dl_vlan=124 actions=group:2
])

OVS_APP_EXIT_AND_WAIT([ovs-ofctl])
OVS_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([ofproto - event filtering (OpenFlow 1.3)])
AT_KEYWORDS([monitor])
OVS_VSWITCHD_START

# Start a monitor, use the required protocol version
ovs-ofctl -O OpenFlow13 monitor br0 --detach --no-chdir --pidfile >monitor.log 2>&1
AT_CAPTURE_FILE([monitor.log])

# Send an OpenFlow13 message (04), OFPT_GET_ASYNC_REQUEST (1a), length (8), xid (0a)
ovs-appctl -t ovs-ofctl ofctl/send 041a00080000000a
ovs-appctl -t ovs-ofctl ofctl/barrier

# Check default setting
read -r -d '' expected <<'EOF'
EOF

AT_CHECK([ofctl_strip < monitor.log], [], [dnl
send: OFPT_GET_ASYNC_REQUEST (OF1.3):
OFPT_GET_ASYNC_REPLY (OF1.3):
 primary:
       PACKET_IN: no_match action
     PORT_STATUS: add delete modify
    FLOW_REMOVED: idle hard delete group_delete
     ROLE_STATUS: (off)
    TABLE_STATUS: (off)
  REQUESTFORWARD: (off)

 secondary:
       PACKET_IN: (off)
     PORT_STATUS: add delete modify
    FLOW_REMOVED: (off)
     ROLE_STATUS: (off)
    TABLE_STATUS: (off)
  REQUESTFORWARD: (off)
OFPT_BARRIER_REPLY (OF1.3):
])

OVS_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([ofproto - ofport_request])
OVS_VSWITCHD_START
add_of_ports br0 1 2 3

set_and_check_specific_ofports () {
    ovs-vsctl set Interface p1 ofport_request="$1" -- \
              set Interface p2 ofport_request="$2" -- \
              set Interface p3 ofport_request="$3"
    ofports=`ovs-vsctl get Interface p1 ofport -- \
                       get Interface p2 ofport -- \
                       get Interface p3 ofport`
    AT_CHECK_UNQUOTED([echo $ofports], [0], [$1 $2 $3
])
}
for pre in      '1 2 3' '1 3 2' '2 1 3' '2 3 1' '3 1 2' '3 2 1'; do
    for post in '1 2 3' '1 3 2' '2 1 3' '2 3 1' '3 1 2' '3 2 1'; do
        echo -----------------------------------------------------------
        echo "Check changing port numbers from $pre to $post"
        set_and_check_specific_ofports $pre
        set_and_check_specific_ofports $post
    done
done

ovs-vsctl del-port p3

set_and_check_poorly_specified_ofports () {
    ovs-vsctl set Interface p1 ofport_request="$1" -- \
              set Interface p2 ofport_request="$2"
    p1=`ovs-vsctl get Interface p1 ofport`
    p2=`ovs-vsctl get Interface p2 ofport`
    echo $p1 $p2

    AT_CHECK([test "$p1" != "$p2"])
    if test "$1" = "$2" && test "$1" != '[[]]'; then
        # One port number must be the requested one.
        AT_CHECK([test "$p1" = "$1" || test "$p2" = "$1"])
        # The other port number must be different (already tested above).
    else
        AT_CHECK([test "$1" = '[[]]' || test "$p1" = "$1"])
        AT_CHECK([test "$2" = '[[]]' || test "$p2" = "$2"])
    fi
}
for pre in      '1 2' '[[]] 2' '1 [[]]' '[[]] [[]]' '2 1' '[[]] 1' '2 [[]]' \
                '1 1' '2 2'; do
    for post in '1 2' '[[]] 2' '1 [[]]' '[[]] [[]]' '2 1' '[[]] 1' '2 [[]]' \
                '1 1' '2 2'; do
        echo -----------------------------------------------------------
        echo "Check changing port numbers from $pre to $post"
        set_and_check_poorly_specified_ofports $pre
        set_and_check_poorly_specified_ofports $post
    done
done
OVS_VSWITCHD_STOP
AT_CLEANUP


AT_SETUP([ofproto - bundle open (OpenFlow 1.4)])
AT_KEYWORDS([monitor])
OVS_VSWITCHD_START

# Start a monitor, use the required protocol version
ovs-ofctl -O OpenFlow14 monitor br0 --detach --no-chdir --pidfile >monitor.log 2>&1
AT_CAPTURE_FILE([monitor.log])

# Send an OpenFlow14 message (05), OFPT_BUNDLE_CONTROL (21), length (10), xid (0a)
ovs-appctl -t ovs-ofctl ofctl/send "05 21 00 10 00 00 00 0a 00 00 00 01 00 00 00 02"
ovs-appctl -t ovs-ofctl ofctl/barrier
OVS_APP_EXIT_AND_WAIT([ovs-ofctl])

AT_CHECK([ofctl_strip < monitor.log], [], [dnl
send: OFPT_BUNDLE_CONTROL (OF1.4):
 bundle_id=0x1 type=OPEN_REQUEST flags=ordered
OFPT_BUNDLE_CONTROL (OF1.4):
 bundle_id=0x1 type=OPEN_REPLY flags=0
OFPT_BARRIER_REPLY (OF1.4):
])

OVS_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([ofproto - bundle double open (OpenFlow 1.4)])
AT_KEYWORDS([monitor])
OVS_VSWITCHD_START

# Start a monitor, use the required protocol version
ovs-ofctl -O OpenFlow14 monitor br0 --detach --no-chdir --pidfile >monitor.log 2>&1
AT_CAPTURE_FILE([monitor.log])

# Send twice an OpenFlow14 message (05), OFPT_BUNDLE_CONTROL (21), length (10), xid (0a)
ovs-appctl -t ovs-ofctl ofctl/send "05 21 00 10 00 00 00 0a 00 00 00 01 00 00 00 02"
ovs-appctl -t ovs-ofctl ofctl/barrier
ovs-appctl -t ovs-ofctl ofctl/send "05 21 00 10 00 00 00 0a 00 00 00 01 00 00 00 02"
ovs-appctl -t ovs-ofctl ofctl/barrier
OVS_APP_EXIT_AND_WAIT([ovs-ofctl])

AT_CHECK([ofctl_strip < monitor.log], [0], [dnl
send: OFPT_BUNDLE_CONTROL (OF1.4):
 bundle_id=0x1 type=OPEN_REQUEST flags=ordered
OFPT_BUNDLE_CONTROL (OF1.4):
 bundle_id=0x1 type=OPEN_REPLY flags=0
OFPT_BARRIER_REPLY (OF1.4):
send: OFPT_BUNDLE_CONTROL (OF1.4):
 bundle_id=0x1 type=OPEN_REQUEST flags=ordered
OFPT_ERROR (OF1.4): OFPBFC_BAD_ID
OFPT_BUNDLE_CONTROL (OF1.4):
 bundle_id=0x1 type=OPEN_REQUEST flags=ordered
OFPT_BARRIER_REPLY (OF1.4):
])

OVS_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([ofproto - bundle close without open (OpenFlow 1.4)])
AT_KEYWORDS([monitor])
OVS_VSWITCHD_START

# Start a monitor, use the required protocol version
ovs-ofctl -O OpenFlow14 monitor br0 --detach --no-chdir --pidfile >monitor.log 2>&1
AT_CAPTURE_FILE([monitor.log])

ovs-appctl -t ovs-ofctl ofctl/send "05 21 00 10 00 00 00 0a 00 00 00 01 00 02 00 02"
ovs-appctl -t ovs-ofctl ofctl/barrier
OVS_APP_EXIT_AND_WAIT([ovs-ofctl])

AT_CHECK([ofctl_strip < monitor.log], [0], [dnl
send: OFPT_BUNDLE_CONTROL (OF1.4):
 bundle_id=0x1 type=CLOSE_REQUEST flags=ordered
OFPT_ERROR (OF1.4): OFPBFC_BAD_ID
OFPT_BUNDLE_CONTROL (OF1.4):
 bundle_id=0x1 type=CLOSE_REQUEST flags=ordered
OFPT_BARRIER_REPLY (OF1.4):
])

OVS_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([ofproto - bundle double close (OpenFlow 1.4)])
AT_KEYWORDS([monitor])
OVS_VSWITCHD_START

# Start a monitor, use the required protocol version
ovs-ofctl -O OpenFlow14 monitor br0 --detach --no-chdir --pidfile >monitor.log 2>&1
AT_CAPTURE_FILE([monitor.log])

# Open, Close, Close
ovs-appctl -t ovs-ofctl ofctl/send "05 21 00 10 00 00 00 0a 00 00 00 01 00 00 00 02"
ovs-appctl -t ovs-ofctl ofctl/barrier
ovs-appctl -t ovs-ofctl ofctl/send "05 21 00 10 00 00 00 0a 00 00 00 01 00 02 00 02"
ovs-appctl -t ovs-ofctl ofctl/barrier
ovs-appctl -t ovs-ofctl ofctl/send "05 21 00 10 00 00 00 0a 00 00 00 01 00 02 00 02"
ovs-appctl -t ovs-ofctl ofctl/barrier
OVS_APP_EXIT_AND_WAIT([ovs-ofctl])

AT_CHECK([ofctl_strip < monitor.log], [0], [dnl
send: OFPT_BUNDLE_CONTROL (OF1.4):
 bundle_id=0x1 type=OPEN_REQUEST flags=ordered
OFPT_BUNDLE_CONTROL (OF1.4):
 bundle_id=0x1 type=OPEN_REPLY flags=0
OFPT_BARRIER_REPLY (OF1.4):
send: OFPT_BUNDLE_CONTROL (OF1.4):
 bundle_id=0x1 type=CLOSE_REQUEST flags=ordered
OFPT_BUNDLE_CONTROL (OF1.4):
 bundle_id=0x1 type=CLOSE_REPLY flags=0
OFPT_BARRIER_REPLY (OF1.4):
send: OFPT_BUNDLE_CONTROL (OF1.4):
 bundle_id=0x1 type=CLOSE_REQUEST flags=ordered
OFPT_ERROR (OF1.4): OFPBFC_BUNDLE_CLOSED
OFPT_BUNDLE_CONTROL (OF1.4):
 bundle_id=0x1 type=CLOSE_REQUEST flags=ordered
OFPT_BARRIER_REPLY (OF1.4):
])

OVS_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([ofproto - bundle close, different flags (OpenFlow 1.4)])
AT_KEYWORDS([monitor])
OVS_VSWITCHD_START

# Start a monitor, use the required protocol version
ovs-ofctl -O OpenFlow14 monitor br0 --detach --no-chdir --pidfile >monitor.log 2>&1
AT_CAPTURE_FILE([monitor.log])

# Open, Close
ovs-appctl -t ovs-ofctl ofctl/send "05 21 00 10 00 00 00 0a 00 00 00 01 00 00 00 02"
ovs-appctl -t ovs-ofctl ofctl/barrier
ovs-appctl -t ovs-ofctl ofctl/send "05 21 00 10 00 00 00 0a 00 00 00 01 00 02 00 01"
ovs-appctl -t ovs-ofctl ofctl/barrier
OVS_APP_EXIT_AND_WAIT([ovs-ofctl])

AT_CHECK([ofctl_strip < monitor.log], [0], [dnl
send: OFPT_BUNDLE_CONTROL (OF1.4):
 bundle_id=0x1 type=OPEN_REQUEST flags=ordered
OFPT_BUNDLE_CONTROL (OF1.4):
 bundle_id=0x1 type=OPEN_REPLY flags=0
OFPT_BARRIER_REPLY (OF1.4):
send: OFPT_BUNDLE_CONTROL (OF1.4):
 bundle_id=0x1 type=CLOSE_REQUEST flags=atomic
OFPT_ERROR (OF1.4): OFPBFC_BAD_FLAGS
OFPT_BUNDLE_CONTROL (OF1.4):
 bundle_id=0x1 type=CLOSE_REQUEST flags=atomic
OFPT_BARRIER_REPLY (OF1.4):
])

OVS_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([ofproto - bundle commit without open (OpenFlow 1.4)])
AT_KEYWORDS([monitor])
OVS_VSWITCHD_START

# Start a monitor, use the required protocol version
ovs-ofctl -O OpenFlow14 monitor br0 --detach --no-chdir --pidfile >monitor.log 2>&1
AT_CAPTURE_FILE([monitor.log])

# Commit
ovs-appctl -t ovs-ofctl ofctl/send "05 21 00 10 00 00 00 0a 00 00 00 01 00 04 00 02"
ovs-appctl -t ovs-ofctl ofctl/barrier
OVS_APP_EXIT_AND_WAIT([ovs-ofctl])

AT_CHECK([ofctl_strip < monitor.log], [0], [dnl
send: OFPT_BUNDLE_CONTROL (OF1.4):
 bundle_id=0x1 type=COMMIT_REQUEST flags=ordered
OFPT_ERROR (OF1.4): OFPBFC_BAD_ID
OFPT_BUNDLE_CONTROL (OF1.4):
 bundle_id=0x1 type=COMMIT_REQUEST flags=ordered
OFPT_BARRIER_REPLY (OF1.4):
])

OVS_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([ofproto - bundle commit, different flags (OpenFlow 1.4)])
AT_KEYWORDS([monitor])
OVS_VSWITCHD_START

# Start a monitor, use the required protocol version
ovs-ofctl -O OpenFlow14 monitor br0 --detach --no-chdir --pidfile >monitor.log 2>&1
AT_CAPTURE_FILE([monitor.log])

# Open, Commit
ovs-appctl -t ovs-ofctl ofctl/send "05 21 00 10 00 00 00 0a 00 00 00 01 00 00 00 02"
ovs-appctl -t ovs-ofctl ofctl/barrier
ovs-appctl -t ovs-ofctl ofctl/send "05 21 00 10 00 00 00 0a 00 00 00 01 00 04 00 01"
ovs-appctl -t ovs-ofctl ofctl/barrier
OVS_APP_EXIT_AND_WAIT([ovs-ofctl])

AT_CHECK([ofctl_strip < monitor.log], [0], [dnl
send: OFPT_BUNDLE_CONTROL (OF1.4):
 bundle_id=0x1 type=OPEN_REQUEST flags=ordered
OFPT_BUNDLE_CONTROL (OF1.4):
 bundle_id=0x1 type=OPEN_REPLY flags=0
OFPT_BARRIER_REPLY (OF1.4):
send: OFPT_BUNDLE_CONTROL (OF1.4):
 bundle_id=0x1 type=COMMIT_REQUEST flags=atomic
OFPT_ERROR (OF1.4): OFPBFC_BAD_FLAGS
OFPT_BUNDLE_CONTROL (OF1.4):
 bundle_id=0x1 type=COMMIT_REQUEST flags=atomic
OFPT_BARRIER_REPLY (OF1.4):
])

OVS_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([ofproto - bundle discard without open (OpenFlow 1.4)])
AT_KEYWORDS([monitor])
OVS_VSWITCHD_START

# Start a monitor, use the required protocol version
ovs-ofctl -O OpenFlow14 monitor br0 --detach --no-chdir --pidfile >monitor.log 2>&1
AT_CAPTURE_FILE([monitor.log])

# Discard
ovs-appctl -t ovs-ofctl ofctl/send "05 21 00 10 00 00 00 0a 00 00 00 01 00 06 00 02"
ovs-appctl -t ovs-ofctl ofctl/barrier
OVS_APP_EXIT_AND_WAIT([ovs-ofctl])

AT_CHECK([ofctl_strip < monitor.log], [0], [dnl
send: OFPT_BUNDLE_CONTROL (OF1.4):
 bundle_id=0x1 type=DISCARD_REQUEST flags=ordered
OFPT_ERROR (OF1.4): OFPBFC_BAD_ID
OFPT_BUNDLE_CONTROL (OF1.4):
 bundle_id=0x1 type=DISCARD_REQUEST flags=ordered
OFPT_BARRIER_REPLY (OF1.4):
])

OVS_VSWITCHD_STOP
AT_CLEANUP


AT_SETUP([ofproto - bundle with multiple flow mods (OpenFlow 1.4)])
OVS_VSWITCHD_START

AT_CHECK([ovs-appctl vlog/set vconn:dbg])

AT_CHECK([ovs-ofctl --no-names del-flows br0])

AT_DATA([flows.txt], [dnl
add idle_timeout=50 in_port=2 dl_src=00:66:77:88:99:aa actions=1
add idle_timeout=60 in_port=2 dl_src=00:77:88:99:aa:bb actions=2
add idle_timeout=70 in_port=2 dl_src=00:88:99:aa:bb:cc actions=3
add idle_timeout=50 in_port=2 dl_src=00:66:77:88:99:aa actions=4
delete
add idle_timeout=50 in_port=2 dl_src=00:66:77:88:99:aa actions=5
add idle_timeout=60 in_port=2 dl_src=00:77:88:99:aa:bb actions=6
add idle_timeout=70 in_port=2 dl_src=00:88:99:aa:bb:cc actions=7
delete in_port=2 dl_src=00:88:99:aa:bb:cc
])

AT_CHECK([ovs-ofctl --no-names --bundle add-flows br0 flows.txt])

AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort], [0], [dnl
 idle_timeout=50, in_port=2,dl_src=00:66:77:88:99:aa actions=output:5
 idle_timeout=60, in_port=2,dl_src=00:77:88:99:aa:bb actions=output:6
NXST_FLOW reply:
])

AT_DATA([flows.txt], [dnl
modify actions=drop
modify_strict in_port=2 dl_src=00:77:88:99:aa:bb actions=7
])

AT_CHECK([ovs-ofctl --no-names --bundle add-flows br0 flows.txt])

AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort], [0], [dnl
 idle_timeout=50, in_port=2,dl_src=00:66:77:88:99:aa actions=drop
 idle_timeout=60, in_port=2,dl_src=00:77:88:99:aa:bb actions=output:7
NXST_FLOW reply:
])

# Adding an existing flow acts as a modify, and delete_strict also works.
AT_DATA([flows.txt], [dnl
add idle_timeout=60 in_port=2 dl_src=00:77:88:99:aa:bb actions=8
delete_strict in_port=2 dl_src=00:66:77:88:99:aa
add in_port=2 dl_src=00:66:77:88:99:aa actions=drop
])

AT_CHECK([ovs-ofctl --no-names --bundle add-flows br0 flows.txt])

AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort], [0], [dnl
 idle_timeout=60, in_port=2,dl_src=00:77:88:99:aa:bb actions=output:8
 in_port=2,dl_src=00:66:77:88:99:aa actions=drop
NXST_FLOW reply:
])

dnl Check logs for OpenFlow trace
# Prevent race.
OVS_WAIT_UNTIL([vconn_sub < ovs-vswitchd.log | test `grep -- "|vconn|DBG|unix: sent (Success): NXST_FLOW reply" | wc -l` -ge 3])
AT_CHECK([print_vconn_debug | vconn_sub | ofctl_strip], [0], [dnl
vconn|DBG|unix: sent (Success): OFPT_HELLO (OF1.5):
 version bitmap: 0x01, 0x02, 0x03, 0x04, 0x05, 0x06
vconn|DBG|unix: received: OFPT_HELLO:
 version bitmap: 0x01
vconn|DBG|unix: negotiated OpenFlow version 0x01 (we support version 0x06 and earlier, peer supports version 0x01)
vconn|DBG|unix: received: OFPT_FLOW_MOD: DEL actions=drop
vconn|DBG|unix: received: OFPT_BARRIER_REQUEST:
vconn|DBG|unix: sent (Success): OFPT_BARRIER_REPLY:
vconn|DBG|unix: sent (Success): OFPT_HELLO (OF1.5):
 version bitmap: 0x01, 0x02, 0x03, 0x04, 0x05, 0x06
vconn|DBG|unix: received: OFPT_HELLO (OF1.4):
 version bitmap: 0x05
vconn|DBG|unix: negotiated OpenFlow version 0x05 (we support version 0x06 and earlier, peer supports version 0x05)
vconn|DBG|unix: received: OFPT_BUNDLE_CONTROL (OF1.4):
 bundle_id=0 type=OPEN_REQUEST flags=atomic ordered
vconn|DBG|unix: sent (Success): OFPT_BUNDLE_CONTROL (OF1.4):
 bundle_id=0 type=OPEN_REPLY flags=0
vconn|DBG|unix: received: OFPT_BUNDLE_ADD_MESSAGE (OF1.4):
 bundle_id=0 flags=atomic ordered
OFPT_FLOW_MOD (OF1.4): ADD in_port=2,dl_src=00:66:77:88:99:aa idle:50 actions=output:1
vconn|DBG|unix: received: OFPT_BUNDLE_ADD_MESSAGE (OF1.4):
 bundle_id=0 flags=atomic ordered
OFPT_FLOW_MOD (OF1.4): ADD in_port=2,dl_src=00:77:88:99:aa:bb idle:60 actions=output:2
vconn|DBG|unix: received: OFPT_BUNDLE_ADD_MESSAGE (OF1.4):
 bundle_id=0 flags=atomic ordered
OFPT_FLOW_MOD (OF1.4): ADD in_port=2,dl_src=00:88:99:aa:bb:cc idle:70 actions=output:3
vconn|DBG|unix: received: OFPT_BUNDLE_ADD_MESSAGE (OF1.4):
 bundle_id=0 flags=atomic ordered
OFPT_FLOW_MOD (OF1.4): ADD in_port=2,dl_src=00:66:77:88:99:aa idle:50 actions=output:4
vconn|DBG|unix: received: OFPT_BUNDLE_ADD_MESSAGE (OF1.4):
 bundle_id=0 flags=atomic ordered
OFPT_FLOW_MOD (OF1.4): DEL table:255 actions=drop
vconn|DBG|unix: received: OFPT_BUNDLE_ADD_MESSAGE (OF1.4):
 bundle_id=0 flags=atomic ordered
OFPT_FLOW_MOD (OF1.4): ADD in_port=2,dl_src=00:66:77:88:99:aa idle:50 actions=output:5
vconn|DBG|unix: received: OFPT_BUNDLE_ADD_MESSAGE (OF1.4):
 bundle_id=0 flags=atomic ordered
OFPT_FLOW_MOD (OF1.4): ADD in_port=2,dl_src=00:77:88:99:aa:bb idle:60 actions=output:6
vconn|DBG|unix: received: OFPT_BUNDLE_ADD_MESSAGE (OF1.4):
 bundle_id=0 flags=atomic ordered
OFPT_FLOW_MOD (OF1.4): ADD in_port=2,dl_src=00:88:99:aa:bb:cc idle:70 actions=output:7
vconn|DBG|unix: received: OFPT_BUNDLE_ADD_MESSAGE (OF1.4):
 bundle_id=0 flags=atomic ordered
OFPT_FLOW_MOD (OF1.4): DEL table:255 in_port=2,dl_src=00:88:99:aa:bb:cc actions=drop
vconn|DBG|unix: received: OFPT_BARRIER_REQUEST (OF1.4):
vconn|DBG|unix: sent (Success): OFPT_BARRIER_REPLY (OF1.4):
vconn|DBG|unix: received: OFPT_BUNDLE_CONTROL (OF1.4):
 bundle_id=0 type=COMMIT_REQUEST flags=atomic ordered
vconn|DBG|unix: sent (Success): OFPT_BUNDLE_CONTROL (OF1.4):
 bundle_id=0 type=COMMIT_REPLY flags=0
vconn|DBG|unix: sent (Success): OFPT_HELLO (OF1.5):
 version bitmap: 0x01, 0x02, 0x03, 0x04, 0x05, 0x06
vconn|DBG|unix: received: OFPT_HELLO:
 version bitmap: 0x01
vconn|DBG|unix: negotiated OpenFlow version 0x01 (we support version 0x06 and earlier, peer supports version 0x01)
vconn|DBG|unix: received: NXT_SET_FLOW_FORMAT: format=nxm
vconn|DBG|unix: received: OFPT_BARRIER_REQUEST:
vconn|DBG|unix: sent (Success): OFPT_BARRIER_REPLY:
vconn|DBG|unix: received: NXST_FLOW request:
vconn|DBG|unix: sent (Success): NXST_FLOW reply:
 idle_timeout=50, in_port=2,dl_src=00:66:77:88:99:aa actions=output:5
 idle_timeout=60, in_port=2,dl_src=00:77:88:99:aa:bb actions=output:6
vconn|DBG|unix: sent (Success): OFPT_HELLO (OF1.5):
 version bitmap: 0x01, 0x02, 0x03, 0x04, 0x05, 0x06
vconn|DBG|unix: received: OFPT_HELLO (OF1.4):
 version bitmap: 0x05
vconn|DBG|unix: negotiated OpenFlow version 0x05 (we support version 0x06 and earlier, peer supports version 0x05)
vconn|DBG|unix: received: OFPT_BUNDLE_CONTROL (OF1.4):
 bundle_id=0 type=OPEN_REQUEST flags=atomic ordered
vconn|DBG|unix: sent (Success): OFPT_BUNDLE_CONTROL (OF1.4):
 bundle_id=0 type=OPEN_REPLY flags=0
vconn|DBG|unix: received: OFPT_BUNDLE_ADD_MESSAGE (OF1.4):
 bundle_id=0 flags=atomic ordered
OFPT_FLOW_MOD (OF1.4): MOD actions=drop
vconn|DBG|unix: received: OFPT_BUNDLE_ADD_MESSAGE (OF1.4):
 bundle_id=0 flags=atomic ordered
OFPT_FLOW_MOD (OF1.4): MOD_STRICT in_port=2,dl_src=00:77:88:99:aa:bb actions=output:7
vconn|DBG|unix: received: OFPT_BARRIER_REQUEST (OF1.4):
vconn|DBG|unix: sent (Success): OFPT_BARRIER_REPLY (OF1.4):
vconn|DBG|unix: received: OFPT_BUNDLE_CONTROL (OF1.4):
 bundle_id=0 type=COMMIT_REQUEST flags=atomic ordered
vconn|DBG|unix: sent (Success): OFPT_BUNDLE_CONTROL (OF1.4):
 bundle_id=0 type=COMMIT_REPLY flags=0
vconn|DBG|unix: sent (Success): OFPT_HELLO (OF1.5):
 version bitmap: 0x01, 0x02, 0x03, 0x04, 0x05, 0x06
vconn|DBG|unix: received: OFPT_HELLO:
 version bitmap: 0x01
vconn|DBG|unix: negotiated OpenFlow version 0x01 (we support version 0x06 and earlier, peer supports version 0x01)
vconn|DBG|unix: received: NXT_SET_FLOW_FORMAT: format=nxm
vconn|DBG|unix: received: OFPT_BARRIER_REQUEST:
vconn|DBG|unix: sent (Success): OFPT_BARRIER_REPLY:
vconn|DBG|unix: received: NXST_FLOW request:
vconn|DBG|unix: sent (Success): NXST_FLOW reply:
 idle_timeout=50, in_port=2,dl_src=00:66:77:88:99:aa actions=drop
 idle_timeout=60, in_port=2,dl_src=00:77:88:99:aa:bb actions=output:7
vconn|DBG|unix: sent (Success): OFPT_HELLO (OF1.5):
 version bitmap: 0x01, 0x02, 0x03, 0x04, 0x05, 0x06
vconn|DBG|unix: received: OFPT_HELLO (OF1.4):
 version bitmap: 0x05
vconn|DBG|unix: negotiated OpenFlow version 0x05 (we support version 0x06 and earlier, peer supports version 0x05)
vconn|DBG|unix: received: OFPT_BUNDLE_CONTROL (OF1.4):
 bundle_id=0 type=OPEN_REQUEST flags=atomic ordered
vconn|DBG|unix: sent (Success): OFPT_BUNDLE_CONTROL (OF1.4):
 bundle_id=0 type=OPEN_REPLY flags=0
vconn|DBG|unix: received: OFPT_BUNDLE_ADD_MESSAGE (OF1.4):
 bundle_id=0 flags=atomic ordered
OFPT_FLOW_MOD (OF1.4): ADD in_port=2,dl_src=00:77:88:99:aa:bb idle:60 actions=output:8
vconn|DBG|unix: received: OFPT_BUNDLE_ADD_MESSAGE (OF1.4):
 bundle_id=0 flags=atomic ordered
OFPT_FLOW_MOD (OF1.4): DEL_STRICT table:255 in_port=2,dl_src=00:66:77:88:99:aa actions=drop
vconn|DBG|unix: received: OFPT_BUNDLE_ADD_MESSAGE (OF1.4):
 bundle_id=0 flags=atomic ordered
OFPT_FLOW_MOD (OF1.4): ADD in_port=2,dl_src=00:66:77:88:99:aa actions=drop
vconn|DBG|unix: received: OFPT_BARRIER_REQUEST (OF1.4):
vconn|DBG|unix: sent (Success): OFPT_BARRIER_REPLY (OF1.4):
vconn|DBG|unix: received: OFPT_BUNDLE_CONTROL (OF1.4):
 bundle_id=0 type=COMMIT_REQUEST flags=atomic ordered
vconn|DBG|unix: sent (Success): OFPT_BUNDLE_CONTROL (OF1.4):
 bundle_id=0 type=COMMIT_REPLY flags=0
vconn|DBG|unix: sent (Success): OFPT_HELLO (OF1.5):
 version bitmap: 0x01, 0x02, 0x03, 0x04, 0x05, 0x06
vconn|DBG|unix: received: OFPT_HELLO:
 version bitmap: 0x01
vconn|DBG|unix: negotiated OpenFlow version 0x01 (we support version 0x06 and earlier, peer supports version 0x01)
vconn|DBG|unix: received: NXT_SET_FLOW_FORMAT: format=nxm
vconn|DBG|unix: received: OFPT_BARRIER_REQUEST:
vconn|DBG|unix: sent (Success): OFPT_BARRIER_REPLY:
vconn|DBG|unix: received: NXST_FLOW request: 
vconn|DBG|unix: sent (Success): NXST_FLOW reply:
 idle_timeout=60, in_port=2,dl_src=00:77:88:99:aa:bb actions=output:8
 in_port=2,dl_src=00:66:77:88:99:aa actions=drop
])

AT_CHECK([grep " flow_mods in the last " ovs-vswitchd.log | sed -e 's/^.*connmgr|INFO|//' | vconn_sub], [0], [dnl
br0<->unix: 1 flow_mods in the last 0 s (1 deletes)
br0<->unix: 9 flow_mods in the last 0 s (7 adds, 2 deletes)
br0<->unix: 2 flow_mods in the last 0 s (2 modifications)
br0<->unix: 3 flow_mods in the last 0 s (2 adds, 1 deletes)
])

OVS_VSWITCHD_STOP
AT_CLEANUP


AT_SETUP([ofproto - failing bundle commit (OpenFlow 1.4)])
OVS_VSWITCHD_START

AT_CHECK([ovs-ofctl del-flows br0])

ovs-ofctl add-flows br0 - <<EOF
idle_timeout=50 in_port=2 dl_src=00:66:77:88:99:aa actions=11
idle_timeout=60 in_port=2 dl_src=00:77:88:99:aa:bb actions=22
idle_timeout=70 in_port=2 dl_src=00:88:99:aa:bb:cc actions=33
EOF
AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort], [0], [dnl
 idle_timeout=50, in_port=2,dl_src=00:66:77:88:99:aa actions=output:11
 idle_timeout=60, in_port=2,dl_src=00:77:88:99:aa:bb actions=output:22
 idle_timeout=70, in_port=2,dl_src=00:88:99:aa:bb:cc actions=output:33
NXST_FLOW reply:
])

# last line uses illegal table number (OVS internal table)
AT_DATA([flows.txt], [dnl
add idle_timeout=50 in_port=2 dl_src=00:66:77:88:99:aa actions=1
add idle_timeout=60 in_port=2 dl_src=00:77:88:99:aa:bb actions=2
add idle_timeout=70 in_port=2 dl_src=00:88:99:aa:bb:cc actions=3
modify idle_timeout=50 in_port=2 dl_src=00:66:77:88:99:aa actions=4
delete
add idle_timeout=50 in_port=2 dl_src=00:66:77:88:99:aa actions=5
add idle_timeout=60 in_port=2 dl_src=00:77:88:99:aa:bb actions=6
add idle_timeout=70 in_port=2 dl_src=00:88:99:aa:bb:cc actions=7
delete in_port=2 dl_src=00:88:99:aa:bb:cc
add table=254 actions=drop
])

AT_CHECK([ovs-ofctl --bundle add-flows br0 flows.txt 2>&1 | sed '/talking to/,$d' | strip_xids],
[0], [dnl
Error OFPBRC_EPERM for: OFPT_FLOW_MOD (OF1.4): ADD table:254 actions=drop
])

AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort], [0], [dnl
 idle_timeout=50, in_port=2,dl_src=00:66:77:88:99:aa actions=output:11
 idle_timeout=60, in_port=2,dl_src=00:77:88:99:aa:bb actions=output:22
 idle_timeout=70, in_port=2,dl_src=00:88:99:aa:bb:cc actions=output:33
NXST_FLOW reply:
])

OVS_VSWITCHD_STOP
AT_CLEANUP


AT_SETUP([ofproto - bundle timeout (OpenFlow 1.4)])
AT_KEYWORDS([monitor])
OVS_VSWITCHD_START

# Start a monitor, use the required protocol version
ovs-ofctl -O OpenFlow14 monitor br0 --detach --no-chdir --pidfile >monitor.log 2>&1
AT_CAPTURE_FILE([monitor.log])

ovs-appctl time/stop

# Send an OpenFlow14 message (05), OFPT_BUNDLE_CONTROL (21), length (10), xid (01)
ovs-appctl -t ovs-ofctl ofctl/send "05 21 00 10 00 00 00 01 00 00 00 01 00 00 00 03"
ovs-appctl time/warp 8000
# Send a bundle flow mod, it should keep the bundle alive.
ovs-appctl -t ovs-ofctl ofctl/send "05 22 00 a0 00 00 00 02 00 00 00 01 00 00 00 03 \
05 0e 00 90 00 00 00 02 00 00 00 00 00 00 00 00 \
00 00 00 00 00 00 00 00 01 00 00 00 00 00 ff ff \
ff ff ff ff ff ff ff ff ff ff ff ff 00 00 00 00 \
00 01 00 42 80 00 00 04 00 00 00 01 80 00 08 06 \
50 54 00 00 00 06 80 00 06 06 50 54 00 00 00 05 \
80 00 0a 02 08 06 80 00 0c 02 00 00 80 00 2a 02 \
00 02 80 00 2c 04 c0 a8 00 02 80 00 2e 04 c0 a8 \
00 01 00 00 00 00 00 00 00 04 00 18 00 00 00 00 \
00 00 00 10 00 00 00 03 00 00 00 00 00 00 00 00 \
"
ovs-appctl time/warp 8000
# Send a bundle close, it should keep the bundle alive.
ovs-appctl -t ovs-ofctl ofctl/send "05 21 00 10 00 00 00 03 00 00 00 01 00 02 00 03"
ovs-appctl time/warp 11000
# Make sure that timeouts are processed after the expiry
ovs-appctl time/warp 1000
# Send a Commit, but too late.
ovs-appctl -t ovs-ofctl ofctl/send "05 21 00 10 00 00 00 04 00 00 00 01 00 04 00 03"
ovs-appctl -t ovs-ofctl ofctl/barrier
OVS_APP_EXIT_AND_WAIT([ovs-ofctl])

AT_CHECK([ofctl_strip < monitor.log], [], [dnl
send: OFPT_BUNDLE_CONTROL (OF1.4):
 bundle_id=0x1 type=OPEN_REQUEST flags=atomic ordered
OFPT_BUNDLE_CONTROL (OF1.4):
 bundle_id=0x1 type=OPEN_REPLY flags=0
send: OFPT_BUNDLE_ADD_MESSAGE (OF1.4):
 bundle_id=0x1 flags=atomic ordered
OFPT_FLOW_MOD (OF1.4): ADD table:1 priority=65535,arp,in_port=1,vlan_tci=0x0000/0x1fff,dl_src=50:54:00:00:00:06,dl_dst=50:54:00:00:00:05,arp_spa=192.168.0.2,arp_tpa=192.168.0.1,arp_op=2 actions=output:3
send: OFPT_BUNDLE_CONTROL (OF1.4):
 bundle_id=0x1 type=CLOSE_REQUEST flags=atomic ordered
OFPT_BUNDLE_CONTROL (OF1.4):
 bundle_id=0x1 type=CLOSE_REPLY flags=0
OFPT_ERROR (OF1.4): OFPBFC_TIMEOUT
OFPT_BUNDLE_CONTROL (OF1.4):
 bundle_id=0x1 type=OPEN_REQUEST flags=atomic ordered
send: OFPT_BUNDLE_CONTROL (OF1.4):
 bundle_id=0x1 type=COMMIT_REQUEST flags=atomic ordered
OFPT_ERROR (OF1.4): OFPBFC_BAD_ID
OFPT_BUNDLE_CONTROL (OF1.4):
 bundle_id=0x1 type=COMMIT_REQUEST flags=atomic ordered
OFPT_BARRIER_REPLY (OF1.4):
])

OVS_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([ofproto - bundle custom timeout (OpenFlow 1.4)])
AT_KEYWORDS([monitor])
OVS_VSWITCHD_START

AT_CHECK([ovs-vsctl set Open_vSwitch . other_config:bundle-idle-timeout=4])

# Start a monitor, use the required protocol version
ovs-ofctl -O OpenFlow14 monitor br0 --detach --no-chdir --pidfile >monitor.log 2>&1
AT_CAPTURE_FILE([monitor.log])

ovs-appctl time/stop

# Send an OpenFlow14 message (05), OFPT_BUNDLE_CONTROL (21), length (10), xid (01)
ovs-appctl -t ovs-ofctl ofctl/send "05 21 00 10 00 00 00 01 00 00 00 01 00 00 00 03"
ovs-appctl time/warp 2000
# Send a bundle flow mod, it should keep the bundle alive.
ovs-appctl -t ovs-ofctl ofctl/send "05 22 00 a0 00 00 00 02 00 00 00 01 00 00 00 03 \
05 0e 00 90 00 00 00 02 00 00 00 00 00 00 00 00 \
00 00 00 00 00 00 00 00 01 00 00 00 00 00 ff ff \
ff ff ff ff ff ff ff ff ff ff ff ff 00 00 00 00 \
00 01 00 42 80 00 00 04 00 00 00 01 80 00 08 06 \
50 54 00 00 00 06 80 00 06 06 50 54 00 00 00 05 \
80 00 0a 02 08 06 80 00 0c 02 00 00 80 00 2a 02 \
00 02 80 00 2c 04 c0 a8 00 02 80 00 2e 04 c0 a8 \
00 01 00 00 00 00 00 00 00 04 00 18 00 00 00 00 \
00 00 00 10 00 00 00 03 00 00 00 00 00 00 00 00 \
"
ovs-appctl time/warp 2000
# Send a bundle close, it should keep the bundle alive.
ovs-appctl -t ovs-ofctl ofctl/send "05 21 00 10 00 00 00 03 00 00 00 01 00 02 00 03"
ovs-appctl time/warp 4000
# Make sure that timeouts are processed after the expiry, but still before the
# current timeout of 4s.
ovs-appctl time/warp 1000
# Send a Commit, but too late.
ovs-appctl -t ovs-ofctl ofctl/send "05 21 00 10 00 00 00 04 00 00 00 01 00 04 00 03"
ovs-appctl -t ovs-ofctl ofctl/barrier
OVS_APP_EXIT_AND_WAIT([ovs-ofctl])

AT_CHECK([ofctl_strip < monitor.log], [], [dnl
send: OFPT_BUNDLE_CONTROL (OF1.4):
 bundle_id=0x1 type=OPEN_REQUEST flags=atomic ordered
OFPT_BUNDLE_CONTROL (OF1.4):
 bundle_id=0x1 type=OPEN_REPLY flags=0
send: OFPT_BUNDLE_ADD_MESSAGE (OF1.4):
 bundle_id=0x1 flags=atomic ordered
OFPT_FLOW_MOD (OF1.4): ADD table:1 priority=65535,arp,in_port=1,vlan_tci=0x0000/0x1fff,dl_src=50:54:00:00:00:06,dl_dst=50:54:00:00:00:05,arp_spa=192.168.0.2,arp_tpa=192.168.0.1,arp_op=2 actions=output:3
send: OFPT_BUNDLE_CONTROL (OF1.4):
 bundle_id=0x1 type=CLOSE_REQUEST flags=atomic ordered
OFPT_BUNDLE_CONTROL (OF1.4):
 bundle_id=0x1 type=CLOSE_REPLY flags=0
OFPT_ERROR (OF1.4): OFPBFC_TIMEOUT
OFPT_BUNDLE_CONTROL (OF1.4):
 bundle_id=0x1 type=OPEN_REQUEST flags=atomic ordered
send: OFPT_BUNDLE_CONTROL (OF1.4):
 bundle_id=0x1 type=COMMIT_REQUEST flags=atomic ordered
OFPT_ERROR (OF1.4): OFPBFC_BAD_ID
OFPT_BUNDLE_CONTROL (OF1.4):
 bundle_id=0x1 type=COMMIT_REQUEST flags=atomic ordered
OFPT_BARRIER_REPLY (OF1.4):
])

OVS_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([ofproto - bundle reset timeout to default (OpenFlow 1.4)])
AT_KEYWORDS([monitor])
OVS_VSWITCHD_START

AT_CHECK([ovs-vsctl set Open_vSwitch . other_config:bundle-idle-timeout=15])
AT_CHECK([ovs-vsctl remove Open_vSwitch . other_config bundle-idle-timeout])

# Start a monitor, use the required protocol version
ovs-ofctl -O OpenFlow14 monitor br0 --detach --no-chdir --pidfile >monitor.log 2>&1
AT_CAPTURE_FILE([monitor.log])

ovs-appctl time/stop

# Send an OpenFlow14 message (05), OFPT_BUNDLE_CONTROL (21), length (10), xid (01)
ovs-appctl -t ovs-ofctl ofctl/send "05 21 00 10 00 00 00 01 00 00 00 01 00 00 00 03"
ovs-appctl time/warp 8000
# Send a bundle flow mod, it should keep the bundle alive.
ovs-appctl -t ovs-ofctl ofctl/send "05 22 00 a0 00 00 00 02 00 00 00 01 00 00 00 03 \
05 0e 00 90 00 00 00 02 00 00 00 00 00 00 00 00 \
00 00 00 00 00 00 00 00 01 00 00 00 00 00 ff ff \
ff ff ff ff ff ff ff ff ff ff ff ff 00 00 00 00 \
00 01 00 42 80 00 00 04 00 00 00 01 80 00 08 06 \
50 54 00 00 00 06 80 00 06 06 50 54 00 00 00 05 \
80 00 0a 02 08 06 80 00 0c 02 00 00 80 00 2a 02 \
00 02 80 00 2c 04 c0 a8 00 02 80 00 2e 04 c0 a8 \
00 01 00 00 00 00 00 00 00 04 00 18 00 00 00 00 \
00 00 00 10 00 00 00 03 00 00 00 00 00 00 00 00 \
"
ovs-appctl time/warp 8000
# Send a bundle close, it should keep the bundle alive.
ovs-appctl -t ovs-ofctl ofctl/send "05 21 00 10 00 00 00 03 00 00 00 01 00 02 00 03"
ovs-appctl time/warp 11000
# Make sure that timeouts are processed after the expiry
ovs-appctl time/warp 1000
# Send a Commit, but too late.
ovs-appctl -t ovs-ofctl ofctl/send "05 21 00 10 00 00 00 04 00 00 00 01 00 04 00 03"
ovs-appctl -t ovs-ofctl ofctl/barrier
OVS_APP_EXIT_AND_WAIT([ovs-ofctl])

AT_CHECK([ofctl_strip < monitor.log], [], [dnl
send: OFPT_BUNDLE_CONTROL (OF1.4):
 bundle_id=0x1 type=OPEN_REQUEST flags=atomic ordered
OFPT_BUNDLE_CONTROL (OF1.4):
 bundle_id=0x1 type=OPEN_REPLY flags=0
send: OFPT_BUNDLE_ADD_MESSAGE (OF1.4):
 bundle_id=0x1 flags=atomic ordered
OFPT_FLOW_MOD (OF1.4): ADD table:1 priority=65535,arp,in_port=1,vlan_tci=0x0000/0x1fff,dl_src=50:54:00:00:00:06,dl_dst=50:54:00:00:00:05,arp_spa=192.168.0.2,arp_tpa=192.168.0.1,arp_op=2 actions=output:3
send: OFPT_BUNDLE_CONTROL (OF1.4):
 bundle_id=0x1 type=CLOSE_REQUEST flags=atomic ordered
OFPT_BUNDLE_CONTROL (OF1.4):
 bundle_id=0x1 type=CLOSE_REPLY flags=0
OFPT_ERROR (OF1.4): OFPBFC_TIMEOUT
OFPT_BUNDLE_CONTROL (OF1.4):
 bundle_id=0x1 type=OPEN_REQUEST flags=atomic ordered
send: OFPT_BUNDLE_CONTROL (OF1.4):
 bundle_id=0x1 type=COMMIT_REQUEST flags=atomic ordered
OFPT_ERROR (OF1.4): OFPBFC_BAD_ID
OFPT_BUNDLE_CONTROL (OF1.4):
 bundle_id=0x1 type=COMMIT_REQUEST flags=atomic ordered
OFPT_BARRIER_REPLY (OF1.4):
])

OVS_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([ofproto - bundle open (OpenFlow 1.3)])
AT_KEYWORDS([monitor])
OVS_VSWITCHD_START

# Start a monitor, use the required protocol version
ovs-ofctl -O OpenFlow13 monitor br0 --detach --no-chdir --pidfile >monitor.log 2>&1
AT_CAPTURE_FILE([monitor.log])

# Send an OpenFlow13 message (04), OFPT_EXPERIMENTER (04), length (0018),
# xid (0000000a), ONF_EXPERIMENTER_ID (4F4E4600),
# ONFT_BUNDLE_CONTROL (2300 = 0x08FC), bundle id (00000001),
# message type (0000), and flags (0002)
ovs-appctl -t ovs-ofctl ofctl/send "04 04 00 18 00 00 00 0a 4F 4E 46 00 00 00 08 FC 00 00 00 01 00 00 00 02"
ovs-appctl -t ovs-ofctl ofctl/barrier
OVS_APP_EXIT_AND_WAIT([ovs-ofctl])

AT_CHECK([ofctl_strip < monitor.log], [], [dnl
send: ONFT_BUNDLE_CONTROL (OF1.3):
 bundle_id=0x1 type=OPEN_REQUEST flags=ordered
ONFT_BUNDLE_CONTROL (OF1.3):
 bundle_id=0x1 type=OPEN_REPLY flags=0
OFPT_BARRIER_REPLY (OF1.3):
])

OVS_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([ofproto - bundle double open (OpenFlow 1.3)])
AT_KEYWORDS([monitor])
OVS_VSWITCHD_START

# Start a monitor, use the required protocol version
ovs-ofctl -O OpenFlow13 monitor br0 --detach --no-chdir --pidfile >monitor.log 2>&1
AT_CAPTURE_FILE([monitor.log])

# Send twice an OpenFlow13 message (04), OFPT_EXPERIMENTER (04), length (0018),
# xid (0000000a), ONF_EXPERIMENTER_ID (4F4E4600),
# ONFT_BUNDLE_CONTROL (2300 = 0x08FC), bundle id (00000001),
# message type (0000), and flags (0002)
ovs-appctl -t ovs-ofctl ofctl/send "04 04 00 18 00 00 00 0a 4F 4E 46 00 00 00 08 FC 00 00 00 01 00 00 00 02"
ovs-appctl -t ovs-ofctl ofctl/barrier
ovs-appctl -t ovs-ofctl ofctl/send "04 04 00 18 00 00 00 0a 4F 4E 46 00 00 00 08 FC 00 00 00 01 00 00 00 02"
ovs-appctl -t ovs-ofctl ofctl/barrier
OVS_APP_EXIT_AND_WAIT([ovs-ofctl])

AT_CHECK([ofctl_strip < monitor.log], [0], [dnl
send: ONFT_BUNDLE_CONTROL (OF1.3):
 bundle_id=0x1 type=OPEN_REQUEST flags=ordered
ONFT_BUNDLE_CONTROL (OF1.3):
 bundle_id=0x1 type=OPEN_REPLY flags=0
OFPT_BARRIER_REPLY (OF1.3):
send: ONFT_BUNDLE_CONTROL (OF1.3):
 bundle_id=0x1 type=OPEN_REQUEST flags=ordered
OFPT_ERROR (OF1.3): OFPBFC_BAD_ID
ONFT_BUNDLE_CONTROL (OF1.3):
 bundle_id=0x1 type=OPEN_REQUEST flags=ordered
OFPT_BARRIER_REPLY (OF1.3):
])

OVS_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([ofproto - bundle close without open (OpenFlow 1.3)])
AT_KEYWORDS([monitor])
OVS_VSWITCHD_START

# Start a monitor, use the required protocol version
ovs-ofctl -O OpenFlow13 monitor br0 --detach --no-chdir --pidfile >monitor.log 2>&1
AT_CAPTURE_FILE([monitor.log])

ovs-appctl -t ovs-ofctl ofctl/send "04 04 00 18 00 00 00 0a 4F 4E 46 00 00 00 08 FC 00 00 00 01 00 02 00 02"
ovs-appctl -t ovs-ofctl ofctl/barrier
OVS_APP_EXIT_AND_WAIT([ovs-ofctl])

AT_CHECK([ofctl_strip < monitor.log], [0], [dnl
send: ONFT_BUNDLE_CONTROL (OF1.3):
 bundle_id=0x1 type=CLOSE_REQUEST flags=ordered
OFPT_ERROR (OF1.3): OFPBFC_BAD_ID
ONFT_BUNDLE_CONTROL (OF1.3):
 bundle_id=0x1 type=CLOSE_REQUEST flags=ordered
OFPT_BARRIER_REPLY (OF1.3):
])

OVS_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([ofproto - bundle double close (OpenFlow 1.3)])
AT_KEYWORDS([monitor])
OVS_VSWITCHD_START

# Start a monitor, use the required protocol version
ovs-ofctl -O OpenFlow13 monitor br0 --detach --no-chdir --pidfile >monitor.log 2>&1
AT_CAPTURE_FILE([monitor.log])

# Open, Close, Close
ovs-appctl -t ovs-ofctl ofctl/send "04 04 00 18 00 00 00 0a 4F 4E 46 00 00 00 08 FC 00 00 00 01 00 00 00 02"
ovs-appctl -t ovs-ofctl ofctl/barrier
ovs-appctl -t ovs-ofctl ofctl/send "04 04 00 18 00 00 00 0a 4F 4E 46 00 00 00 08 FC 00 00 00 01 00 02 00 02"
ovs-appctl -t ovs-ofctl ofctl/barrier
ovs-appctl -t ovs-ofctl ofctl/send "04 04 00 18 00 00 00 0a 4F 4E 46 00 00 00 08 FC 00 00 00 01 00 02 00 02"
ovs-appctl -t ovs-ofctl ofctl/barrier
OVS_APP_EXIT_AND_WAIT([ovs-ofctl])

AT_CHECK([ofctl_strip < monitor.log], [0], [dnl
send: ONFT_BUNDLE_CONTROL (OF1.3):
 bundle_id=0x1 type=OPEN_REQUEST flags=ordered
ONFT_BUNDLE_CONTROL (OF1.3):
 bundle_id=0x1 type=OPEN_REPLY flags=0
OFPT_BARRIER_REPLY (OF1.3):
send: ONFT_BUNDLE_CONTROL (OF1.3):
 bundle_id=0x1 type=CLOSE_REQUEST flags=ordered
ONFT_BUNDLE_CONTROL (OF1.3):
 bundle_id=0x1 type=CLOSE_REPLY flags=0
OFPT_BARRIER_REPLY (OF1.3):
send: ONFT_BUNDLE_CONTROL (OF1.3):
 bundle_id=0x1 type=CLOSE_REQUEST flags=ordered
OFPT_ERROR (OF1.3): OFPBFC_BUNDLE_CLOSED
ONFT_BUNDLE_CONTROL (OF1.3):
 bundle_id=0x1 type=CLOSE_REQUEST flags=ordered
OFPT_BARRIER_REPLY (OF1.3):
])

OVS_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([ofproto - bundle close, different flags (OpenFlow 1.3)])
AT_KEYWORDS([monitor])
OVS_VSWITCHD_START

# Start a monitor, use the required protocol version
ovs-ofctl -O OpenFlow13 monitor br0 --detach --no-chdir --pidfile >monitor.log 2>&1
AT_CAPTURE_FILE([monitor.log])

# Open, Close
ovs-appctl -t ovs-ofctl ofctl/send "04 04 00 18 00 00 00 0a 4F 4E 46 00 00 00 08 FC 00 00 00 01 00 00 00 02"
ovs-appctl -t ovs-ofctl ofctl/barrier
ovs-appctl -t ovs-ofctl ofctl/send "04 04 00 18 00 00 00 0a 4F 4E 46 00 00 00 08 FC 00 00 00 01 00 02 00 01"
ovs-appctl -t ovs-ofctl ofctl/barrier
OVS_APP_EXIT_AND_WAIT([ovs-ofctl])

AT_CHECK([ofctl_strip < monitor.log], [0], [dnl
send: ONFT_BUNDLE_CONTROL (OF1.3):
 bundle_id=0x1 type=OPEN_REQUEST flags=ordered
ONFT_BUNDLE_CONTROL (OF1.3):
 bundle_id=0x1 type=OPEN_REPLY flags=0
OFPT_BARRIER_REPLY (OF1.3):
send: ONFT_BUNDLE_CONTROL (OF1.3):
 bundle_id=0x1 type=CLOSE_REQUEST flags=atomic
OFPT_ERROR (OF1.3): OFPBFC_BAD_FLAGS
ONFT_BUNDLE_CONTROL (OF1.3):
 bundle_id=0x1 type=CLOSE_REQUEST flags=atomic
OFPT_BARRIER_REPLY (OF1.3):
])

OVS_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([ofproto - bundle commit without open (OpenFlow 1.3)])
AT_KEYWORDS([monitor])
OVS_VSWITCHD_START

# Start a monitor, use the required protocol version
ovs-ofctl -O OpenFlow13 monitor br0 --detach --no-chdir --pidfile >monitor.log 2>&1
AT_CAPTURE_FILE([monitor.log])

# Commit
ovs-appctl -t ovs-ofctl ofctl/send "04 04 00 18 00 00 00 0a 4F 4E 46 00 00 00 08 FC 00 00 00 01 00 04 00 02"
ovs-appctl -t ovs-ofctl ofctl/barrier
OVS_APP_EXIT_AND_WAIT([ovs-ofctl])

AT_CHECK([ofctl_strip < monitor.log], [0], [dnl
send: ONFT_BUNDLE_CONTROL (OF1.3):
 bundle_id=0x1 type=COMMIT_REQUEST flags=ordered
OFPT_ERROR (OF1.3): OFPBFC_BAD_ID
ONFT_BUNDLE_CONTROL (OF1.3):
 bundle_id=0x1 type=COMMIT_REQUEST flags=ordered
OFPT_BARRIER_REPLY (OF1.3):
])

OVS_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([ofproto - bundle commit, different flags (OpenFlow 1.3)])
AT_KEYWORDS([monitor])
OVS_VSWITCHD_START

# Start a monitor, use the required protocol version
ovs-ofctl -O OpenFlow13 monitor br0 --detach --no-chdir --pidfile >monitor.log 2>&1
AT_CAPTURE_FILE([monitor.log])

# Open, Commit
ovs-appctl -t ovs-ofctl ofctl/send "04 04 00 18 00 00 00 0a 4F 4E 46 00 00 00 08 FC 00 00 00 01 00 00 00 02"
ovs-appctl -t ovs-ofctl ofctl/barrier
ovs-appctl -t ovs-ofctl ofctl/send "04 04 00 18 00 00 00 0a 4F 4E 46 00 00 00 08 FC 00 00 00 01 00 04 00 01"
ovs-appctl -t ovs-ofctl ofctl/barrier
OVS_APP_EXIT_AND_WAIT([ovs-ofctl])

AT_CHECK([ofctl_strip < monitor.log], [0], [dnl
send: ONFT_BUNDLE_CONTROL (OF1.3):
 bundle_id=0x1 type=OPEN_REQUEST flags=ordered
ONFT_BUNDLE_CONTROL (OF1.3):
 bundle_id=0x1 type=OPEN_REPLY flags=0
OFPT_BARRIER_REPLY (OF1.3):
send: ONFT_BUNDLE_CONTROL (OF1.3):
 bundle_id=0x1 type=COMMIT_REQUEST flags=atomic
OFPT_ERROR (OF1.3): OFPBFC_BAD_FLAGS
ONFT_BUNDLE_CONTROL (OF1.3):
 bundle_id=0x1 type=COMMIT_REQUEST flags=atomic
OFPT_BARRIER_REPLY (OF1.3):
])

OVS_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([ofproto - bundle discard without open (OpenFlow 1.3)])
AT_KEYWORDS([monitor])
OVS_VSWITCHD_START

# Start a monitor, use the required protocol version
ovs-ofctl -O OpenFlow13 monitor br0 --detach --no-chdir --pidfile >monitor.log 2>&1
AT_CAPTURE_FILE([monitor.log])

# Discard
ovs-appctl -t ovs-ofctl ofctl/send "04 04 00 18 00 00 00 0a 4F 4E 46 00 00 00 08 FC 00 00 00 01 00 06 00 02"
ovs-appctl -t ovs-ofctl ofctl/barrier
OVS_APP_EXIT_AND_WAIT([ovs-ofctl])

AT_CHECK([ofctl_strip < monitor.log], [0], [dnl
send: ONFT_BUNDLE_CONTROL (OF1.3):
 bundle_id=0x1 type=DISCARD_REQUEST flags=ordered
OFPT_ERROR (OF1.3): OFPBFC_BAD_ID
ONFT_BUNDLE_CONTROL (OF1.3):
 bundle_id=0x1 type=DISCARD_REQUEST flags=ordered
OFPT_BARRIER_REPLY (OF1.3):
])

OVS_VSWITCHD_STOP
AT_CLEANUP


AT_SETUP([ofproto - bundle with multiple flow mods (OpenFlow 1.3)])
OVS_VSWITCHD_START

AT_CHECK([ovs-appctl vlog/set vconn:dbg])

AT_CHECK([ovs-ofctl --no-names del-flows br0])

AT_DATA([flows.txt], [dnl
add idle_timeout=50 in_port=2 dl_src=00:66:77:88:99:aa actions=1
add idle_timeout=60 in_port=2 dl_src=00:77:88:99:aa:bb actions=2
add idle_timeout=70 in_port=2 dl_src=00:88:99:aa:bb:cc actions=3
add idle_timeout=50 in_port=2 dl_src=00:66:77:88:99:aa actions=4
delete
add idle_timeout=50 in_port=2 dl_src=00:66:77:88:99:aa actions=5
add idle_timeout=60 in_port=2 dl_src=00:77:88:99:aa:bb actions=6
add idle_timeout=70 in_port=2 dl_src=00:88:99:aa:bb:cc actions=7
delete in_port=2 dl_src=00:88:99:aa:bb:cc
])

AT_CHECK([ovs-ofctl -O OpenFlow13 --no-names --bundle add-flows br0 flows.txt])

AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort], [0], [dnl
 idle_timeout=50, in_port=2,dl_src=00:66:77:88:99:aa actions=output:5
 idle_timeout=60, in_port=2,dl_src=00:77:88:99:aa:bb actions=output:6
NXST_FLOW reply:
])

AT_DATA([flows.txt], [dnl
modify actions=drop
modify_strict in_port=2 dl_src=00:77:88:99:aa:bb actions=7
])

AT_CHECK([ovs-ofctl -O OpenFlow13 --no-names --bundle add-flows br0 flows.txt])

AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort], [0], [dnl
 idle_timeout=50, in_port=2,dl_src=00:66:77:88:99:aa actions=drop
 idle_timeout=60, in_port=2,dl_src=00:77:88:99:aa:bb actions=output:7
NXST_FLOW reply:
])

# Adding an existing flow acts as a modify, and delete_strict also works.
AT_DATA([flows.txt], [dnl
add idle_timeout=60 in_port=2 dl_src=00:77:88:99:aa:bb actions=8
delete_strict in_port=2 dl_src=00:66:77:88:99:aa
add in_port=2 dl_src=00:66:77:88:99:aa actions=drop
])

AT_CHECK([ovs-ofctl -O OpenFlow13 --bundle --no-names add-flows br0 flows.txt])

AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort], [0], [dnl
 idle_timeout=60, in_port=2,dl_src=00:77:88:99:aa:bb actions=output:8
 in_port=2,dl_src=00:66:77:88:99:aa actions=drop
NXST_FLOW reply:
])

dnl Check logs for OpenFlow trace
# Prevent race.
OVS_WAIT_UNTIL([vconn_sub < ovs-vswitchd.log | test `grep -- "|vconn|DBG|unix: sent (Success): NXST_FLOW reply" | wc -l` -ge 3])
AT_CHECK([print_vconn_debug | vconn_sub | ofctl_strip], [0], [dnl
vconn|DBG|unix: sent (Success): OFPT_HELLO (OF1.5):
 version bitmap: 0x01, 0x02, 0x03, 0x04, 0x05, 0x06
vconn|DBG|unix: received: OFPT_HELLO:
 version bitmap: 0x01
vconn|DBG|unix: negotiated OpenFlow version 0x01 (we support version 0x06 and earlier, peer supports version 0x01)
vconn|DBG|unix: received: OFPT_FLOW_MOD: DEL actions=drop
vconn|DBG|unix: received: OFPT_BARRIER_REQUEST:
vconn|DBG|unix: sent (Success): OFPT_BARRIER_REPLY:
vconn|DBG|unix: sent (Success): OFPT_HELLO (OF1.5):
 version bitmap: 0x01, 0x02, 0x03, 0x04, 0x05, 0x06
vconn|DBG|unix: received: OFPT_HELLO (OF1.3):
 version bitmap: 0x04
vconn|DBG|unix: negotiated OpenFlow version 0x04 (we support version 0x06 and earlier, peer supports version 0x04)
vconn|DBG|unix: received: ONFT_BUNDLE_CONTROL (OF1.3):
 bundle_id=0 type=OPEN_REQUEST flags=atomic ordered
vconn|DBG|unix: sent (Success): ONFT_BUNDLE_CONTROL (OF1.3):
 bundle_id=0 type=OPEN_REPLY flags=0
vconn|DBG|unix: received: ONFT_BUNDLE_ADD_MESSAGE (OF1.3):
 bundle_id=0 flags=atomic ordered
OFPT_FLOW_MOD (OF1.3): ADD in_port=2,dl_src=00:66:77:88:99:aa idle:50 actions=output:1
vconn|DBG|unix: received: ONFT_BUNDLE_ADD_MESSAGE (OF1.3):
 bundle_id=0 flags=atomic ordered
OFPT_FLOW_MOD (OF1.3): ADD in_port=2,dl_src=00:77:88:99:aa:bb idle:60 actions=output:2
vconn|DBG|unix: received: ONFT_BUNDLE_ADD_MESSAGE (OF1.3):
 bundle_id=0 flags=atomic ordered
OFPT_FLOW_MOD (OF1.3): ADD in_port=2,dl_src=00:88:99:aa:bb:cc idle:70 actions=output:3
vconn|DBG|unix: received: ONFT_BUNDLE_ADD_MESSAGE (OF1.3):
 bundle_id=0 flags=atomic ordered
OFPT_FLOW_MOD (OF1.3): ADD in_port=2,dl_src=00:66:77:88:99:aa idle:50 actions=output:4
vconn|DBG|unix: received: ONFT_BUNDLE_ADD_MESSAGE (OF1.3):
 bundle_id=0 flags=atomic ordered
OFPT_FLOW_MOD (OF1.3): DEL table:255 actions=drop
vconn|DBG|unix: received: ONFT_BUNDLE_ADD_MESSAGE (OF1.3):
 bundle_id=0 flags=atomic ordered
OFPT_FLOW_MOD (OF1.3): ADD in_port=2,dl_src=00:66:77:88:99:aa idle:50 actions=output:5
vconn|DBG|unix: received: ONFT_BUNDLE_ADD_MESSAGE (OF1.3):
 bundle_id=0 flags=atomic ordered
OFPT_FLOW_MOD (OF1.3): ADD in_port=2,dl_src=00:77:88:99:aa:bb idle:60 actions=output:6
vconn|DBG|unix: received: ONFT_BUNDLE_ADD_MESSAGE (OF1.3):
 bundle_id=0 flags=atomic ordered
OFPT_FLOW_MOD (OF1.3): ADD in_port=2,dl_src=00:88:99:aa:bb:cc idle:70 actions=output:7
vconn|DBG|unix: received: ONFT_BUNDLE_ADD_MESSAGE (OF1.3):
 bundle_id=0 flags=atomic ordered
OFPT_FLOW_MOD (OF1.3): DEL table:255 in_port=2,dl_src=00:88:99:aa:bb:cc actions=drop
vconn|DBG|unix: received: OFPT_BARRIER_REQUEST (OF1.3):
vconn|DBG|unix: sent (Success): OFPT_BARRIER_REPLY (OF1.3):
vconn|DBG|unix: received: ONFT_BUNDLE_CONTROL (OF1.3):
 bundle_id=0 type=COMMIT_REQUEST flags=atomic ordered
vconn|DBG|unix: sent (Success): ONFT_BUNDLE_CONTROL (OF1.3):
 bundle_id=0 type=COMMIT_REPLY flags=0
vconn|DBG|unix: sent (Success): OFPT_HELLO (OF1.5):
 version bitmap: 0x01, 0x02, 0x03, 0x04, 0x05, 0x06
vconn|DBG|unix: received: OFPT_HELLO:
 version bitmap: 0x01
vconn|DBG|unix: negotiated OpenFlow version 0x01 (we support version 0x06 and earlier, peer supports version 0x01)
vconn|DBG|unix: received: NXT_SET_FLOW_FORMAT: format=nxm
vconn|DBG|unix: received: OFPT_BARRIER_REQUEST:
vconn|DBG|unix: sent (Success): OFPT_BARRIER_REPLY:
vconn|DBG|unix: received: NXST_FLOW request:
vconn|DBG|unix: sent (Success): NXST_FLOW reply:
 idle_timeout=50, in_port=2,dl_src=00:66:77:88:99:aa actions=output:5
 idle_timeout=60, in_port=2,dl_src=00:77:88:99:aa:bb actions=output:6
vconn|DBG|unix: sent (Success): OFPT_HELLO (OF1.5):
 version bitmap: 0x01, 0x02, 0x03, 0x04, 0x05, 0x06
vconn|DBG|unix: received: OFPT_HELLO (OF1.3):
 version bitmap: 0x04
vconn|DBG|unix: negotiated OpenFlow version 0x04 (we support version 0x06 and earlier, peer supports version 0x04)
vconn|DBG|unix: received: ONFT_BUNDLE_CONTROL (OF1.3):
 bundle_id=0 type=OPEN_REQUEST flags=atomic ordered
vconn|DBG|unix: sent (Success): ONFT_BUNDLE_CONTROL (OF1.3):
 bundle_id=0 type=OPEN_REPLY flags=0
vconn|DBG|unix: received: ONFT_BUNDLE_ADD_MESSAGE (OF1.3):
 bundle_id=0 flags=atomic ordered
OFPT_FLOW_MOD (OF1.3): MOD actions=drop
vconn|DBG|unix: received: ONFT_BUNDLE_ADD_MESSAGE (OF1.3):
 bundle_id=0 flags=atomic ordered
OFPT_FLOW_MOD (OF1.3): MOD_STRICT in_port=2,dl_src=00:77:88:99:aa:bb actions=output:7
vconn|DBG|unix: received: OFPT_BARRIER_REQUEST (OF1.3):
vconn|DBG|unix: sent (Success): OFPT_BARRIER_REPLY (OF1.3):
vconn|DBG|unix: received: ONFT_BUNDLE_CONTROL (OF1.3):
 bundle_id=0 type=COMMIT_REQUEST flags=atomic ordered
vconn|DBG|unix: sent (Success): ONFT_BUNDLE_CONTROL (OF1.3):
 bundle_id=0 type=COMMIT_REPLY flags=0
vconn|DBG|unix: sent (Success): OFPT_HELLO (OF1.5):
 version bitmap: 0x01, 0x02, 0x03, 0x04, 0x05, 0x06
vconn|DBG|unix: received: OFPT_HELLO:
 version bitmap: 0x01
vconn|DBG|unix: negotiated OpenFlow version 0x01 (we support version 0x06 and earlier, peer supports version 0x01)
vconn|DBG|unix: received: NXT_SET_FLOW_FORMAT: format=nxm
vconn|DBG|unix: received: OFPT_BARRIER_REQUEST:
vconn|DBG|unix: sent (Success): OFPT_BARRIER_REPLY:
vconn|DBG|unix: received: NXST_FLOW request:
vconn|DBG|unix: sent (Success): NXST_FLOW reply:
 idle_timeout=50, in_port=2,dl_src=00:66:77:88:99:aa actions=drop
 idle_timeout=60, in_port=2,dl_src=00:77:88:99:aa:bb actions=output:7
vconn|DBG|unix: sent (Success): OFPT_HELLO (OF1.5):
 version bitmap: 0x01, 0x02, 0x03, 0x04, 0x05, 0x06
vconn|DBG|unix: received: OFPT_HELLO (OF1.3):
 version bitmap: 0x04
vconn|DBG|unix: negotiated OpenFlow version 0x04 (we support version 0x06 and earlier, peer supports version 0x04)
vconn|DBG|unix: received: ONFT_BUNDLE_CONTROL (OF1.3):
 bundle_id=0 type=OPEN_REQUEST flags=atomic ordered
vconn|DBG|unix: sent (Success): ONFT_BUNDLE_CONTROL (OF1.3):
 bundle_id=0 type=OPEN_REPLY flags=0
vconn|DBG|unix: received: ONFT_BUNDLE_ADD_MESSAGE (OF1.3):
 bundle_id=0 flags=atomic ordered
OFPT_FLOW_MOD (OF1.3): ADD in_port=2,dl_src=00:77:88:99:aa:bb idle:60 actions=output:8
vconn|DBG|unix: received: ONFT_BUNDLE_ADD_MESSAGE (OF1.3):
 bundle_id=0 flags=atomic ordered
OFPT_FLOW_MOD (OF1.3): DEL_STRICT table:255 in_port=2,dl_src=00:66:77:88:99:aa actions=drop
vconn|DBG|unix: received: ONFT_BUNDLE_ADD_MESSAGE (OF1.3):
 bundle_id=0 flags=atomic ordered
OFPT_FLOW_MOD (OF1.3): ADD in_port=2,dl_src=00:66:77:88:99:aa actions=drop
vconn|DBG|unix: received: OFPT_BARRIER_REQUEST (OF1.3):
vconn|DBG|unix: sent (Success): OFPT_BARRIER_REPLY (OF1.3):
vconn|DBG|unix: received: ONFT_BUNDLE_CONTROL (OF1.3):
 bundle_id=0 type=COMMIT_REQUEST flags=atomic ordered
vconn|DBG|unix: sent (Success): ONFT_BUNDLE_CONTROL (OF1.3):
 bundle_id=0 type=COMMIT_REPLY flags=0
vconn|DBG|unix: sent (Success): OFPT_HELLO (OF1.5):
 version bitmap: 0x01, 0x02, 0x03, 0x04, 0x05, 0x06
vconn|DBG|unix: received: OFPT_HELLO:
 version bitmap: 0x01
vconn|DBG|unix: negotiated OpenFlow version 0x01 (we support version 0x06 and earlier, peer supports version 0x01)
vconn|DBG|unix: received: NXT_SET_FLOW_FORMAT: format=nxm
vconn|DBG|unix: received: OFPT_BARRIER_REQUEST:
vconn|DBG|unix: sent (Success): OFPT_BARRIER_REPLY:
vconn|DBG|unix: received: NXST_FLOW request: 
vconn|DBG|unix: sent (Success): NXST_FLOW reply:
 idle_timeout=60, in_port=2,dl_src=00:77:88:99:aa:bb actions=output:8
 in_port=2,dl_src=00:66:77:88:99:aa actions=drop
])

OVS_VSWITCHD_STOP
AT_CLEANUP


AT_SETUP([ofproto - failing bundle add message (OpenFlow 1.3)])
OVS_VSWITCHD_START

AT_CHECK([ovs-ofctl del-flows br0])

ovs-ofctl add-flows br0 - <<EOF
idle_timeout=50 in_port=2 dl_src=00:66:77:88:99:aa actions=11
idle_timeout=60 in_port=2 dl_src=00:77:88:99:aa:bb actions=22
idle_timeout=70 in_port=2 dl_src=00:88:99:aa:bb:cc actions=33
EOF
AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort], [0], [dnl
 idle_timeout=50, in_port=2,dl_src=00:66:77:88:99:aa actions=output:11
 idle_timeout=60, in_port=2,dl_src=00:77:88:99:aa:bb actions=output:22
 idle_timeout=70, in_port=2,dl_src=00:88:99:aa:bb:cc actions=output:33
NXST_FLOW reply:
])

# last line uses illegal table number (OVS internal table)
AT_DATA([flows.txt], [dnl
add idle_timeout=50 in_port=2 dl_src=00:66:77:88:99:aa actions=1
add idle_timeout=60 in_port=2 dl_src=00:77:88:99:aa:bb actions=2
add idle_timeout=70 in_port=2 dl_src=00:88:99:aa:bb:cc actions=3
modify idle_timeout=50 in_port=2 dl_src=00:66:77:88:99:aa actions=4
delete
add idle_timeout=50 in_port=2 dl_src=00:66:77:88:99:aa actions=5
add idle_timeout=60 in_port=2 dl_src=00:77:88:99:aa:bb actions=6
add idle_timeout=70 in_port=2 dl_src=00:88:99:aa:bb:cc actions=7
delete in_port=2 dl_src=00:88:99:aa:bb:cc
add table=254 actions=drop
])

AT_CHECK([ovs-ofctl -O OpenFlow13 --bundle add-flows br0 flows.txt 2>&1 | sed '/talking to/,$d' | strip_xids],
[0], [dnl
Error OFPBRC_EPERM for: OFPT_FLOW_MOD (OF1.3): ADD table:254 actions=drop
])

AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort], [0], [dnl
 idle_timeout=50, in_port=2,dl_src=00:66:77:88:99:aa actions=output:11
 idle_timeout=60, in_port=2,dl_src=00:77:88:99:aa:bb actions=output:22
 idle_timeout=70, in_port=2,dl_src=00:88:99:aa:bb:cc actions=output:33
NXST_FLOW reply:
])

OVS_VSWITCHD_STOP
AT_CLEANUP


AT_SETUP([ofproto - failing bundle commit (OpenFlow 1.3)])
OVS_VSWITCHD_START

AT_CHECK([ovs-ofctl del-flows br0])

# Invalid group numbers are detected at commit time
AT_DATA([flows.txt], [dnl
add idle_timeout=50 in_port=2 dl_src=00:66:77:88:99:aa actions=group:1
add idle_timeout=60 in_port=2 dl_src=00:77:88:99:aa:bb actions=group:2
add idle_timeout=70 in_port=2 dl_src=00:88:99:aa:bb:cc actions=group:3
])

AT_CHECK([ovs-ofctl -O OpenFlow13 --bundle add-flows br0 flows.txt 2>&1 | sed '/talking to/,$d' | strip_xids],
[0], [dnl
Error OFPBAC_BAD_OUT_GROUP for: OFPT_FLOW_MOD (OF1.3): ADD in_port=2,dl_src=00:66:77:88:99:aa idle:50 actions=group:1
Error OFPBFC_MSG_FAILED for: ONFT_BUNDLE_CONTROL (OF1.3):
 bundle_id=0 type=COMMIT_REQUEST flags=atomic ordered
])

AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort], [0], [dnl
NXST_FLOW reply:
])

OVS_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([ofproto - monitor flows with tun_md])
OVS_VSWITCHD_START

AT_CHECK([ovs-ofctl add-tlv-map br0 "{class=0xffff,type=0,len=4}->tun_metadata0"])
AT_CHECK([ovs-ofctl add-flow br0 tun_metadata0=0x1,actions=drop])

AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip], [0], [dnl
NXST_FLOW reply:
 tun_metadata0=0x1 actions=drop
])

AT_CAPTURE_FILE([ofctl_monitor.log])
dnl Usually ovs-ofctl monitor outputs on stderr, but the first message here
dnl is put on stdout, because it is handled by ofctl in dump_transaction()
dnl and not in monitor_vconn().
AT_CHECK([ovs-ofctl monitor br0 65534 watch: --detach --no-chdir --pidfile >ofctl_monitor.log 2>&1])

OVS_WAIT_UNTIL([test `wc -l < ofctl_monitor.log` -ge 2])

AT_CHECK([cat ofctl_monitor.log | ofctl_strip], [0], [dnl
NXST_FLOW_MONITOR reply:
 event=ADDED table=0 cookie=0 tun_metadata0=0x1
])

AT_CHECK([ovs-ofctl del-flows br0])

OVS_WAIT_UNTIL([test `wc -l < ofctl_monitor.log` -ge 4])

AT_CHECK([cat ofctl_monitor.log | ofctl_strip], [0], [dnl
NXST_FLOW_MONITOR reply:
 event=ADDED table=0 cookie=0 tun_metadata0=0x1
NXST_FLOW_MONITOR reply:
 event=DELETED reason=delete table=0 cookie=0 tun_metadata0=0x1
])

OVS_APP_EXIT_AND_WAIT([ovs-ofctl])

dnl Check that vswitchd hasn't crashed
AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip], [0], [dnl
NXST_FLOW reply:
])

OVS_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([ofproto - flow mod with tunnel metadata])
AT_KEYWORDS([ofp-actions])
OVS_VSWITCHD_START

AT_CHECK([ovs-ofctl add-tlv-map br0 "{class=0xffff,type=0,len=4}->tun_metadata0"])
AT_CHECK([ovs-ofctl add-flow br0 "in_port=1 actions=move:tun_metadata0[[0..31]]->NXM_NX_REG0[[]]"])

dnl Check the length of tun_metadata0 in the replied OXM header.
dnl Ignore the first 0x50 bytes of hex dump from the reply msg since the NXM
dnl header that describes the tunnel metadata starts at offset 0x50.
AT_CHECK([ovs-ofctl dump-flows br0 -mmmm], [0], [stdout])
AT_CHECK([sed -e 's/duration=[[0-9.]]*s/duration=?s/' -e 's/idle_age=[[0-9]]*/idle_age=?/' -e '/^000000[[0-4]]0 / d' stdout | strip_xids], [0], [dnl
NXST_FLOW reply:
 cookie=0x0, duration=?s, table=0, n_packets=0, n_bytes=0, idle_age=?, in_port=1 actions=move:NXM_NX_TUN_METADATA0[[0..31]]->NXM_NX_REG0[[]]
00000050  ff ff 00 18 00 00 23 20-00 06 00 20 00 00 00 00 |......# ... ....|
00000060  00 01 50 04 00 01 00 04-                        |..P.....        |
])

dnl Check actions that may use tun_metadata
AT_CHECK([ovs-ofctl add-flow br0 "in_port=2 actions=move:tun_metadata1[[0..31]]->NXM_NX_REG0[[]]"], [1], [], [stderr])
AT_CHECK([strip_xids < stderr | sed '/FLOW_MOD/,$d'], [0], [dnl
OFPT_ERROR: NXFMFC_INVALID_TLV_FIELD
])

AT_CHECK([ovs-ofctl add-flow br0 "in_port=2 actions=move:tun_metadata0[[32..63]]->NXM_NX_REG0[[]]"], [1], [], [stderr])
AT_CHECK([strip_xids < stderr | sed '/FLOW_MOD/,$d'], [0], [dnl
OFPT_ERROR: OFPBAC_BAD_SET_LEN
])

AT_CHECK([ovs-ofctl add-flow br0 "in_port=2 actions=push:tun_metadata1[[0..31]]"], [1], [], [stderr])
AT_CHECK([strip_xids < stderr | sed '/FLOW_MOD/,$d'], [0], [dnl
OFPT_ERROR: NXFMFC_INVALID_TLV_FIELD
])

AT_CHECK([ovs-ofctl add-flow br0 "in_port=2 actions=pop:tun_metadata0[[32..63]]"], [1], [], [stderr])
AT_CHECK([strip_xids < stderr | sed '/FLOW_MOD/,$d'], [0], [dnl
OFPT_ERROR: OFPBAC_BAD_SET_LEN
])

AT_CHECK([ovs-ofctl add-flow br0 "in_port=3, actions=load:0x11223344->tun_metadata1"], [1], [], [stderr])
AT_CHECK([strip_xids < stderr | sed '/FLOW_MOD/,$d'], [0], [dnl
OFPT_ERROR: NXFMFC_INVALID_TLV_FIELD
])

AT_CHECK([ovs-ofctl add-flow br0 "in_port=2 actions=output:tun_metadata1[[0..31]]"], [1], [], [stderr])
AT_CHECK([strip_xids < stderr | sed '/FLOW_MOD/,$d'], [0], [dnl
OFPT_ERROR: NXFMFC_INVALID_TLV_FIELD
])

AT_CHECK([ovs-ofctl add-flow br0 "in_port=2 actions=output:tun_metadata0[[32..63]]"], [1], [], [stderr])
AT_CHECK([strip_xids < stderr | sed '/FLOW_MOD/,$d'], [0], [dnl
OFPT_ERROR: OFPBAC_BAD_SET_LEN
])

AT_CHECK([ovs-ofctl add-flow br0 "in_port=2 actions=multipath(eth_src,50,modulo_n,1,0,tun_metadata1[[0..31]])"], [1], [], [stderr])
AT_CHECK([strip_xids < stderr | sed '/FLOW_MOD/,$d'], [0], [dnl
OFPT_ERROR: NXFMFC_INVALID_TLV_FIELD
])

AT_CHECK([ovs-ofctl add-flow br0 "in_port=2 actions=multipath(eth_src,50,modulo_n,1,0,tun_metadata0[[32..63]])"], [1], [], [stderr])
AT_CHECK([strip_xids < stderr | sed '/FLOW_MOD/,$d'], [0], [dnl
OFPT_ERROR: OFPBAC_BAD_SET_LEN
])

AT_CHECK([ovs-ofctl add-flow br0 "in_port=2 actions=bundle_load(eth_src,50,hrw,ofport,tun_metadata1[[0..31]], members:4,8)"], [1], [], [stderr])
AT_CHECK([strip_xids < stderr | sed '/FLOW_MOD/,$d'], [0], [dnl
OFPT_ERROR: NXFMFC_INVALID_TLV_FIELD
])

AT_CHECK([ovs-ofctl add-flow br0 "in_port=2 actions=bundle_load(eth_src,50,hrw,ofport,tun_metadata0[[32..63]], members:4,8)"], [1], [], [stderr])
AT_CHECK([strip_xids < stderr | sed '/FLOW_MOD/,$d'], [0], [dnl
OFPT_ERROR: OFPBAC_BAD_SET_LEN
])

AT_CHECK([ovs-ofctl add-flow br0 "in_port=2 actions=learn(tun_metadata1[[0..31]]=reg0[[0..31]])"], [1], [], [stderr])
AT_CHECK([strip_xids < stderr | sed '/FLOW_MOD/,$d'], [0], [dnl
OFPT_ERROR: NXFMFC_INVALID_TLV_FIELD
])

AT_CHECK([ovs-ofctl add-flow br0 "in_port=2 actions=learn(tun_metadata0[[32..63]]=reg0[[0..31]])"], [1], [], [stderr])
AT_CHECK([strip_xids < stderr | sed '/FLOW_MOD/,$d'], [0], [dnl
OFPT_ERROR: OFPBAC_BAD_SET_LEN
])

AT_CHECK([ovs-ofctl add-flow br0 "in_port=2 actions=clone(move:tun_metadata1[[0..31]]->reg0[[0..31]])"], [1], [], [stderr])
AT_CHECK([strip_xids < stderr | sed '/FLOW_MOD/,$d'], [0], [dnl
OFPT_ERROR: NXFMFC_INVALID_TLV_FIELD
])

AT_CHECK([ovs-ofctl add-flow br0 "in_port=2 actions=clone(move:tun_metadata0[[32..63]]->reg0[[0..31]])"], [1], [], [stderr])
AT_CHECK([strip_xids < stderr | sed '/FLOW_MOD/,$d'], [0], [dnl
OFPT_ERROR: OFPBAC_BAD_SET_LEN
])

AT_CHECK([ovs-ofctl add-flow br0 "ip actions=ct(commit,zone=tun_metadata1[[0..15]],exec(set_field:0x01->ct_mark))"], [1], [], [stderr])
AT_CHECK([strip_xids < stderr | sed '/FLOW_MOD/,$d'], [0], [dnl
OFPT_ERROR: NXFMFC_INVALID_TLV_FIELD
])

AT_CHECK([ovs-ofctl add-flow br0 "ip actions=ct(commit,zone=tun_metadata0[[32..47]],exec(set_field:0x01->ct_mark))"], [1], [], [stderr])
AT_CHECK([strip_xids < stderr | sed '/FLOW_MOD/,$d'], [0], [dnl
OFPT_ERROR: OFPBAC_BAD_SET_LEN
])

AT_CHECK([ovs-ofctl add-flow br0 "ip actions=ct(commit,zone=1,exec(move:tun_metadata1[[0..31]]->ct_mark))"], [1], [], [stderr])
AT_CHECK([strip_xids < stderr | sed '/FLOW_MOD/,$d'], [0], [dnl
OFPT_ERROR: NXFMFC_INVALID_TLV_FIELD
])

AT_CHECK([ovs-ofctl add-flow br0 "ip actions=ct(commit,zone=1,exec(move:tun_metadata0[[32..63]]->ct_mark))"], [1], [], [stderr])
AT_CHECK([strip_xids < stderr | sed '/FLOW_MOD/,$d'], [0], [dnl
OFPT_ERROR: OFPBAC_BAD_SET_LEN
])

dnl Check match field with tun_metadata
AT_CHECK([ovs-ofctl add-flow br0 "tun_metadata0=0x11223344 actions=output:2"], [0], [], [stderr])
AT_CHECK([ovs-ofctl add-flow br0 "tun_metadata1=0x11223344 actions=output:2"], [1], [], [stderr])
AT_CHECK([strip_xids < stderr | sed '/FLOW_MOD/,$d'], [0], [dnl
OFPT_ERROR: NXFMFC_INVALID_TLV_FIELD
])

AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip], [0], [dnl)
NXST_FLOW reply:
 in_port=1 actions=move:NXM_NX_TUN_METADATA0[[0..31]]->NXM_NX_REG0[[]]
 tun_metadata0=0x11223344 actions=output:2
])

OVS_VSWITCHD_STOP(["/NXFMFC_INVALID_TLV_FIELD/d
/tun_metadata0/d
/OFPBAC_BAD_SET_LEN/d"])
AT_CLEANUP

AT_SETUP([ofproto - flush flows, groups, and meters for controller change])
AT_KEYWORDS([flow flows group group meter])
OVS_VSWITCHD_START

add_flow_group_and_meter () {
    AT_CHECK([ovs-ofctl add-flow br0 in_port=1,actions=2])
    AT_CHECK([ovs-ofctl -O OpenFlow11 add-group br0 group_id=1234,type=all,bucket=output:10
    AT_CHECK([ovs-ofctl -O OpenFlow13 add-meter br0 'meter=1 pktps burst stats bands=type=drop rate=1 burst_size=1'])
])
}

verify_added () {
    AT_CHECK([ovs-ofctl --no-stats dump-flows br0], [0], [dnl
 in_port=1 actions=output:2
])
    AT_CHECK([ovs-ofctl -O OpenFlow11 dump-groups br0], [0], [dnl
OFPST_GROUP_DESC reply (OF1.1) (xid=0x2):
 group_id=1234,type=all,bucket=actions=output:10
])
    AT_CHECK([ovs-ofctl -O OpenFlow13 dump-meters br0], [0], [dnl
OFPST_METER_CONFIG reply (OF1.3) (xid=0x2):
meter=1 pktps burst stats bands=
type=drop rate=1 burst_size=1
])
}

verify_deleted () {
    AT_CHECK([ovs-ofctl --no-stats dump-flows br0])
    AT_CHECK([ovs-ofctl -O OpenFlow11 dump-groups br0], [0], [dnl
OFPST_GROUP_DESC reply (OF1.1) (xid=0x2):
])
    AT_CHECK([ovs-ofctl -O OpenFlow13 dump-meters br0], [0], [dnl
OFPST_METER_CONFIG reply (OF1.3) (xid=0x2):
])
}

# Add flow, group, meter and check that they're there, without a controller.
add_flow_group_and_meter
verify_added

# Set up a controller and verify that the flow and group were deleted,
# then add them back.
AT_CHECK([ovs-vsctl set-controller br0 'tcp:<invalid>:6653'])
verify_deleted
add_flow_group_and_meter
verify_added

# Change the controller and verify that the flow and group are still there.
AT_CHECK([ovs-vsctl set-controller br0 'tcp:<invalid2>:6653'])
verify_added

# Clear the controller and verify that the flow and group were deleted.
AT_CHECK([ovs-vsctl del-controller br0])
verify_deleted

OVS_VSWITCHD_STOP(["/<invalid/d"])
AT_CLEANUP

AT_SETUP([ofproto - implicit mask of ipv4 proto with invalid proto field])
OVS_VSWITCHD_START
add_of_ports br0 1 2

AT_DATA([flows.txt], [dnl
table=0 in_port=1 priority=90,ip,nw_dst=192.168.1.20,actions=mod_nw_dst:192.168.20.20,output=2
table=0 in_port=1 priority=89,ip,nw_dst=192.168.1.21,actions=mod_nw_src:192.168.20.21,output=2
table=0 in_port=1 priority=88,ip,nw_dst=192.168.1.10,actions=dec_ttl,output=2
table=0 in_port=1 priority=87,ip,nw_dst=192.168.1.19,actions=mod_nw_ttl:8,output=2
table=0 in_port=1 priority=86,ip,nw_dst=192.168.1.18,actions=mod_nw_ecn:2,output=2
table=0 in_port=1 priority=85,ip,nw_dst=192.168.1.17,actions=mod_nw_tos:0x40,output=2
table=0 in_port=1 priority=84,ip,nw_dst=192.168.1.16,actions=set_field:192.168.20.26->nw_dst,output=2
table=0 in_port=1 priority=83,ip,nw_dst=192.168.1.15,actions=set_field:192.168.21.26->nw_src,output=2
table=0 in_port=1 priority=82,ip,nw_dst=192.168.1.14,actions=set_field:0x40->nw_tos,output=2
table=0 in_port=1 priority=0,actions=drop
])
AT_CHECK([ovs-ofctl del-flows br0])
AT_CHECK([ovs-ofctl add-flows br0 flows.txt])

dnl send a proto 0 packet to try and poison the DP flow path
AT_CHECK([ovs-appctl netdev-dummy/receive p1 \
 '5054000000075054000000050800450000548de140004000289fc0a801c4c0a8011408003bf60002001bbf080a640000000032ad010000000000101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f3031323334353637'])

AT_CHECK([ovs-appctl dpctl/dump-flows], [0], [dnl
flow-dump from the main thread:
recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(dst=192.168.1.20,proto=0,frag=no), packets:0, bytes:0, used:never, actions:2
])

dnl Send ICMP for mod nw_src and mod nw_dst
AT_CHECK([ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=192.168.1.1,dst=192.168.1.21,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)'])
AT_CHECK([ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=192.168.1.1,dst=192.168.1.20,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)'])

dnl send ICMP that will dec TTL
AT_CHECK([ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=192.168.1.1,dst=192.168.1.10,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)'])

dnl send ICMP that will mod TTL
AT_CHECK([ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=192.168.1.1,dst=192.168.1.19,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)'])

dnl send ICMP that will mod ECN
AT_CHECK([ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=192.168.1.1,dst=192.168.1.18,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)'])

dnl send ICMP that will mod TOS
AT_CHECK([ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=192.168.1.1,dst=192.168.1.17,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)'])

dnl send ICMP that will set DST
AT_CHECK([ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=192.168.1.1,dst=192.168.1.16,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)'])

dnl send ICMP that will set SRC
AT_CHECK([ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=192.168.1.1,dst=192.168.1.15,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)'])

dnl send ICMP that will set TOS
AT_CHECK([ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=192.168.1.1,dst=192.168.1.14,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)'])

AT_CHECK([ovs-appctl dpctl/dump-flows | sort], [0], [dnl
flow-dump from the main thread:
recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(dst=192.168.1.10,proto=1,ttl=64,frag=no), packets:0, bytes:0, used:never, actions:set(ipv4(ttl=63)),2
recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(dst=192.168.1.14,proto=1,tos=0/0xfc,frag=no), packets:0, bytes:0, used:never, actions:set(ipv4(tos=0x40/0xfc)),2
recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(dst=192.168.1.16,proto=1,frag=no), packets:0, bytes:0, used:never, actions:set(ipv4(dst=192.168.20.26)),2
recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(dst=192.168.1.17,proto=1,tos=0/0xfc,frag=no), packets:0, bytes:0, used:never, actions:set(ipv4(tos=0x40/0xfc)),2
recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(dst=192.168.1.18,proto=1,tos=0/0x3,frag=no), packets:0, bytes:0, used:never, actions:set(ipv4(tos=0x2/0x3)),2
recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(dst=192.168.1.19,proto=1,ttl=64,frag=no), packets:0, bytes:0, used:never, actions:set(ipv4(ttl=8)),2
recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(dst=192.168.1.20,proto=0,frag=no), packets:0, bytes:0, used:never, actions:2
recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(dst=192.168.1.20,proto=1,frag=no), packets:0, bytes:0, used:never, actions:set(ipv4(dst=192.168.20.20)),2
recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(src=192.168.1.1,dst=192.168.1.15,proto=1,frag=no), packets:0, bytes:0, used:never, actions:set(ipv4(src=192.168.21.26)),2
recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(src=192.168.1.1,dst=192.168.1.21,proto=1,frag=no), packets:0, bytes:0, used:never, actions:set(ipv4(src=192.168.20.21)),2
])

OVS_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([ofproto - implicit mask of ipv6 proto with HOPOPT field])
OVS_VSWITCHD_START
add_of_ports br0 1 2

AT_DATA([flows.txt], [dnl
table=0 in_port=1 priority=77,ip6,ipv6_dst=111:db8::3,actions=dec_ttl,output=2
table=0 in_port=1 priority=76,ip6,ipv6_dst=111:db8::4,actions=mod_nw_ttl:8,output=2
table=0 in_port=1 priority=75,ip6,ipv6_dst=111:db8::5,actions=mod_nw_ecn:2,output=2
table=0 in_port=1 priority=74,ip6,ipv6_dst=111:db8::6,actions=mod_nw_tos:0x40,output=2
table=0 in_port=1 priority=73,ip6,ipv6_dst=111:db8::7,actions=set_field:2112:db8::2->ipv6_dst,output=2
table=0 in_port=1 priority=72,ip6,ipv6_dst=111:db8::8,actions=set_field:2112:db8::3->ipv6_src,output=2
table=0 in_port=1 priority=72,ip6,ipv6_dst=111:db8::9,actions=set_field:44->ipv6_label,output=2
table=0 in_port=1 priority=0,actions=drop
])
AT_CHECK([ovs-ofctl del-flows br0])
AT_CHECK([ovs-ofctl add-flows br0 flows.txt])

dnl send a proto 0 packet to try and poison the DP flow path
AT_CHECK([ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x86dd),ipv6(src=2001:db8::1,dst=111:db8::3,proto=0,tclass=0,hlimit=64,frag=no)'])

AT_CHECK([ovs-appctl dpctl/dump-flows], [0], [dnl
flow-dump from the main thread:
recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x86dd),ipv6(dst=111:db8::3,proto=0,hlimit=0,frag=no), packets:0, bytes:0, used:never, actions:userspace(pid=0,controller(reason=2,dont_send=0,continuation=0,recirc_id=1,rule_cookie=0,controller_id=0,max_len=65535))
])

dnl Send ICMP for mod nw_src and mod nw_dst
AT_CHECK([ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x86dd),ipv6(src=2001:db8::1,dst=111:db8::3,proto=1,tclass=0,hlimit=64,frag=no),icmpv6(type=0,code=8)'])
AT_CHECK([ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x86dd),ipv6(src=2001:db8::1,dst=111:db8::4,proto=1,tclass=0,hlimit=64,frag=no),icmpv6(type=0,code=8)'])

dnl send ICMP that will dec TTL
AT_CHECK([ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x86dd),ipv6(src=2001:db8::1,dst=111:db8::5,proto=1,tclass=0,hlimit=64,frag=no),icmpv6(type=0,code=8)'])

dnl send ICMP that will mod TTL
AT_CHECK([ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x86dd),ipv6(src=2001:db8::1,dst=111:db8::6,proto=1,tclass=0,hlimit=64,frag=no),icmpv6(type=0,code=8)'])

dnl send ICMP that will mod ECN
AT_CHECK([ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x86dd),ipv6(src=2001:db8::1,dst=111:db8::7,proto=1,tclass=0,hlimit=64,frag=no),icmpv6(type=0,code=8)'])

dnl send ICMP that will mod TOS
AT_CHECK([ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x86dd),ipv6(src=2001:db8::1,dst=111:db8::8,proto=1,tclass=0,hlimit=64,frag=no),icmpv6(type=0,code=8)'])

dnl send ICMP that will set LABEL
AT_CHECK([ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x86dd),ipv6(src=2001:db8::1,dst=111:db8::9,proto=1,tclass=0,hlimit=64,frag=no),icmpv6(type=0,code=8)'])

AT_CHECK([ovs-appctl dpctl/dump-flows | sort], [0], [dnl
flow-dump from the main thread:
recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x86dd),ipv6(dst=111:db8::3,proto=0,hlimit=0,frag=no), packets:0, bytes:0, used:never, actions:userspace(pid=0,controller(reason=2,dont_send=0,continuation=0,recirc_id=1,rule_cookie=0,controller_id=0,max_len=65535))
recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x86dd),ipv6(dst=111:db8::3,proto=1,hlimit=64,frag=no), packets:0, bytes:0, used:never, actions:set(ipv6(hlimit=63)),2
recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x86dd),ipv6(dst=111:db8::4,proto=1,hlimit=64,frag=no), packets:0, bytes:0, used:never, actions:set(ipv6(hlimit=8)),2
recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x86dd),ipv6(dst=111:db8::5,proto=1,tclass=0/0x3,frag=no), packets:0, bytes:0, used:never, actions:set(ipv6(tclass=0x2/0x3)),2
recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x86dd),ipv6(dst=111:db8::6,proto=1,tclass=0/0xfc,frag=no), packets:0, bytes:0, used:never, actions:set(ipv6(tclass=0x40/0xfc)),2
recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x86dd),ipv6(dst=111:db8::7,proto=1,frag=no), packets:0, bytes:0, used:never, actions:set(ipv6(dst=2112:db8::2)),2
recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x86dd),ipv6(dst=111:db8::9,label=0,proto=1,frag=no), packets:0, bytes:0, used:never, actions:set(ipv6(label=0x2c)),2
recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x86dd),ipv6(src=2001:db8::1,dst=111:db8::8,proto=1,frag=no), packets:0, bytes:0, used:never, actions:set(ipv6(src=2112:db8::3)),2
])

OVS_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([ofproto - implicit mask of ARP OPer field])
OVS_VSWITCHD_START
add_of_ports br0 1 2

AT_DATA([flows.txt], [dnl
table=0 in_port=1 priority=77,arp,arp_sha=00:01:02:03:04:06,actions=set_field:0x1->arp_op,2
table=0 in_port=1 priority=76,arp,arp_sha=00:01:02:03:04:07,actions=set_field:00:02:03:04:05:06->arp_sha,2
table=0 in_port=1 priority=75,arp,arp_sha=00:01:02:03:04:08,actions=set_field:ff:00:00:00:00:ff->arp_tha,2
table=0 in_port=1 priority=74,arp,arp_sha=00:01:02:03:04:09,actions=set_field:172.31.110.26->arp_spa,2
table=0 in_port=1 priority=73,arp,arp_sha=00:01:02:03:04:0a,actions=set_field:172.31.110.10->arp_tpa,2
table=0 in_port=1 priority=1,actions=drop
])

AT_CHECK([ovs-ofctl del-flows br0])
AT_CHECK([ovs-ofctl add-flows br0 flows.txt])

dnl Send op == 0 packet
AT_CHECK([ovs-appctl netdev-dummy/receive p1 \
 'ffffffffffffaa55aa550000080600010800060400000001020304070c0a00010000000000000c0a0002'])

AT_CHECK([ovs-appctl dpctl/dump-flows], [0], [dnl
flow-dump from the main thread:
recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x0806),arp(op=0,sha=00:01:02:03:04:07), packets:0, bytes:0, used:never, actions:2
])

dnl Send op 2 -> set op
AT_CHECK([ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0806),arp(sip=172.31.110.1,tip=172.31.110.25,op=2,sha=00:01:02:03:04:06,tha=ff:ff:ff:ff:ff:ff)'])

dnl Send op 1 -> set SHA
AT_CHECK([ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0806),arp(sip=172.31.110.1,tip=172.31.110.25,op=1,sha=00:01:02:03:04:07,tha=ff:ff:ff:ff:ff:ff)'])

dnl Send op 1 -> set THA
AT_CHECK([ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0806),arp(sip=172.31.110.1,tip=172.31.110.25,op=1,sha=00:01:02:03:04:08,tha=ff:ff:ff:ff:ff:ff)'])

dnl Send op 1 -> set SIP
AT_CHECK([ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0806),arp(sip=172.31.110.1,tip=172.31.110.25,op=1,sha=00:01:02:03:04:09,tha=ff:ff:ff:ff:ff:ff)'])

dnl Send op 1 -> set TIP
AT_CHECK([ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0806),arp(sip=172.31.110.1,tip=172.31.110.25,op=1,sha=00:01:02:03:04:0a,tha=ff:ff:ff:ff:ff:ff)'])

AT_CHECK([ovs-appctl dpctl/dump-flows | sort], [0], [dnl
flow-dump from the main thread:
recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x0806),arp(op=0,sha=00:01:02:03:04:07), packets:0, bytes:0, used:never, actions:2
recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x0806),arp(op=1,sha=00:01:02:03:04:07), packets:0, bytes:0, used:never, actions:userspace(pid=0,slow_path(action))
recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x0806),arp(op=1,sha=00:01:02:03:04:08,tha=ff:ff:ff:ff:ff:ff), packets:0, bytes:0, used:never, actions:userspace(pid=0,slow_path(action))
recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x0806),arp(op=2,sha=00:01:02:03:04:06), packets:0, bytes:0, used:never, actions:userspace(pid=0,slow_path(action))
recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x0806),arp(sip=172.31.110.1,op=1,sha=00:01:02:03:04:09), packets:0, bytes:0, used:never, actions:userspace(pid=0,slow_path(action))
recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x0806),arp(tip=172.31.110.25,op=1,sha=00:01:02:03:04:0a), packets:0, bytes:0, used:never, actions:userspace(pid=0,slow_path(action))
])

OVS_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([ofproto - configure inactivity probe interval])

# Set 6 second inactivity probe interval (default is 5 seconds).
OVS_VSWITCHD_START([set-controller br0 unix:testcontroller \
                   -- set Controller br0 inactivity_probe=6000], [], [],
                   [-vfile:rconn:dbg])

# Start test openflow controller.
AT_CHECK([ovs-testcontroller -vsyslog:off --detach --no-chdir --pidfile punix:testcontroller],
         [0], [ignore])
on_exit 'kill `cat ovs-testcontroller.pid`'
OVS_WAIT_UNTIL([test -e testcontroller])

# After 6 seconds of inactivity there should be a log message.
OVS_WAIT_UNTIL([grep "idle 6 seconds, sending inactivity probe" ovs-vswitchd.log])

# Restart ovs-vswitchd with an empty ovs-vswitchd log file.
OVS_APP_EXIT_AND_WAIT([ovs-vswitchd])
mv ovs-vswitchd.log ovs-vswitchd_1.log
AT_CHECK([ovs-vswitchd --enable-dummy --disable-system --disable-system-route --detach \
         --no-chdir --pidfile --log-file -vfile:rconn:dbg -vvconn -vofproto_dpif -vunixctl],
         [0], [], [stderr])

# After 6 seconds of inactivity there should be a log message.
OVS_WAIT_UNTIL([grep "idle 6 seconds, sending inactivity probe" ovs-vswitchd.log])
OVS_VSWITCHD_STOP(["/br0<->unix:testcontroller: connection failed/d"])
AT_CLEANUP
