Rewrite IP ToS/DSCP: Add IP ToS/DSCP field rewrite feature

This commit is contained in:
Mikio Hara
2009-07-01 11:28:51 -07:00
parent b008eb8126
commit 680f63b514
11 changed files with 506 additions and 220 deletions
+34
View File
@@ -195,6 +195,34 @@ set_nw_addr(struct sk_buff *skb, struct sw_flow_key *key,
return skb;
}
static struct sk_buff *
set_nw_tos(struct sk_buff *skb, struct sw_flow_key *key,
const struct ofp_action_header *ah)
{
struct ofp_action_nw_tos *nt = (struct ofp_action_nw_tos *)ah;
uint16_t eth_proto = ntohs(key->dl_type);
if (eth_proto == ETH_P_IP) {
struct iphdr *nh = ip_hdr(skb);
uint8_t new, *field;
/* JeanII : Set only 6 bits, don't clobber ECN */
new = (nt->nw_tos & 0xFC) | (nh->tos & 0x03);
/* Get address of field */
field = &nh->tos;
/* jklee : ip tos field is not included in TCP pseudo header.
* Need magic as update_csum() don't work with 8 bits. */
update_csum(&nh->check, skb, htons((uint16_t)*field),
htons((uint16_t)new), 0);
/* Update in packet */
*field = new;
}
return skb;
}
static struct sk_buff *
set_tp_port(struct sk_buff *skb, struct sw_flow_key *key,
const struct ofp_action_header *ah)
@@ -293,6 +321,12 @@ static const struct openflow_action of_actions[] = {
NULL,
set_nw_addr
},
[OFPAT_SET_NW_TOS] = {
sizeof(struct ofp_action_nw_tos),
sizeof(struct ofp_action_nw_tos),
NULL,
set_nw_tos
},
[OFPAT_SET_TP_SRC] = {
sizeof(struct ofp_action_tp_port),
sizeof(struct ofp_action_tp_port),
+56 -56
View File
@@ -1,6 +1,6 @@
/* Copyright (c) 2008 The Board of Trustees of The Leland Stanford
* Junior University
*
*
* We are making the OpenFlow specification and associated documentation
* (Software) available for public use and benefit with the expectation
* that others will use, modify and enhance the Software and contribute
@@ -13,10 +13,10 @@
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
@@ -25,7 +25,7 @@
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*
* The name and trademarks of copyright holder(s) may NOT be used in
* advertising or publicity pertaining to the Software or any
* derivatives without specific, written prior permission.
@@ -61,7 +61,7 @@
#endif
/* The most significant bit being set in the version field indicates an
* experimental OpenFlow version.
* experimental OpenFlow version.
*/
#define OFP_VERSION 0x97
@@ -79,18 +79,18 @@ enum ofp_port {
OFPP_MAX = 0xff00,
/* Fake output "ports". */
OFPP_IN_PORT = 0xfff8, /* Send the packet out the input port. This
virtual port must be explicitly used
in order to send back out of the input
OFPP_IN_PORT = 0xfff8, /* Send the packet out the input port. This
virtual port must be explicitly used
in order to send back out of the input
port. */
OFPP_TABLE = 0xfff9, /* Perform actions in flow table.
OFPP_TABLE = 0xfff9, /* Perform actions in flow table.
NB: This can only be the destination
port for packet-out messages. */
OFPP_NORMAL = 0xfffa, /* Process with normal L2/L3 switching. */
OFPP_FLOOD = 0xfffb, /* All physical ports except input port and
OFPP_FLOOD = 0xfffb, /* All physical ports except input port and
those disabled by STP. */
OFPP_ALL = 0xfffc, /* All physical ports except input port. */
OFPP_CONTROLLER = 0xfffd, /* Send to controller. */
OFPP_CONTROLLER = 0xfffd, /* Send to controller. */
OFPP_LOCAL = 0xfffe, /* Local openflow "port". */
OFPP_NONE = 0xffff /* Not associated with a physical port. */
};
@@ -178,7 +178,7 @@ enum ofp_capabilities {
/* Flags to indicate behavior of the physical port. These flags are
* used in ofp_phy_port to describe the current configuration. They are
* used in the ofp_port_mod message to configure the port's behavior.
* used in the ofp_port_mod message to configure the port's behavior.
*/
enum ofp_port_config {
OFPPC_PORT_DOWN = 1 << 0, /* Port is administratively down. */
@@ -286,15 +286,15 @@ struct ofp_port_mod {
struct ofp_header header;
uint16_t port_no;
uint8_t hw_addr[OFP_ETH_ALEN]; /* The hardware address is not
configurable. This is used to
sanity-check the request, so it must
configurable. This is used to
sanity-check the request, so it must
be the same as returned in an
ofp_phy_port struct. */
uint32_t config; /* Bitmap of OFPPC_* flags. */
uint32_t mask; /* Bitmap of OFPPC_* flags to be changed. */
uint32_t advertise; /* Bitmap of "ofp_port_features"s. Zero all
uint32_t advertise; /* Bitmap of "ofp_port_features"s. Zero all
bits to prevent any action taking place. */
uint8_t pad[4]; /* Pad to 64-bits. */
};
@@ -315,7 +315,7 @@ struct ofp_packet_in {
uint8_t reason; /* Reason packet is being sent (one of OFPR_*) */
uint8_t pad;
uint8_t data[0]; /* Ethernet frame, halfway through 32-bit word,
so the IP header is 32-bit aligned. The
so the IP header is 32-bit aligned. The
amount of data is inferred from the length
field in the header. Because of padding,
offsetof(struct ofp_packet_in, data) ==
@@ -338,9 +338,9 @@ enum ofp_action_type {
OFPAT_VENDOR = 0xffff
};
/* Action structure for OFPAT_OUTPUT, which sends packets out 'port'.
* When the 'port' is the OFPP_CONTROLLER, 'max_len' indicates the max
* number of bytes to send. A 'max_len' of zero means the entire packet
/* Action structure for OFPAT_OUTPUT, which sends packets out 'port'.
* When the 'port' is the OFPP_CONTROLLER, 'max_len' indicates the max
* number of bytes to send. A 'max_len' of zero means the entire packet
* should be sent. */
struct ofp_action_output {
uint16_t type; /* OFPAT_OUTPUT. */
@@ -406,25 +406,25 @@ struct ofp_action_nw_tos {
uint8_t nw_tos; /* IP ToS/DSCP (6 bits). */
uint8_t pad[3];
};
OFP_ASSERT(sizeof(struct ofp_action_nw_addr) == 8);
OFP_ASSERT(sizeof(struct ofp_action_nw_tos) == 8);
/* Action header for OFPAT_VENDOR. The rest of the body is vendor-defined. */
struct ofp_action_vendor_header {
uint16_t type; /* OFPAT_VENDOR. */
uint16_t len; /* Length is 8. */
uint32_t vendor; /* Vendor ID, which takes the same form
as in "struct ofp_vendor_header". */
uint32_t vendor; /* Vendor ID, which takes the same form
as in "struct ofp_vendor_header". */
};
OFP_ASSERT(sizeof(struct ofp_action_vendor_header) == 8);
/* Action header that is common to all actions. The length includes the
* header and any padding used to make the action 64-bit aligned.
* header and any padding used to make the action 64-bit aligned.
* NB: The length of an action *must* always be a multiple of eight. */
struct ofp_action_header {
uint16_t type; /* One of OFPAT_*. */
uint16_t len; /* Length of action, including this
header. This is the length of action,
including any padding to make it
uint16_t len; /* Length of action, including this
header. This is the length of action,
including any padding to make it
64-bit aligned. */
uint8_t pad[4];
};
@@ -437,8 +437,8 @@ struct ofp_packet_out {
uint16_t in_port; /* Packet's input port (OFPP_NONE if none). */
uint16_t actions_len; /* Size of action array in bytes. */
struct ofp_action_header actions[0]; /* Actions. */
/* uint8_t data[0]; */ /* Packet data. The length is inferred
from the length field in the header.
/* uint8_t data[0]; */ /* Packet data. The length is inferred
from the length field in the header.
(Only meaningful if buffer_id == -1.) */
};
OFP_ASSERT(sizeof(struct ofp_packet_out) == 16);
@@ -483,7 +483,7 @@ enum ofp_flow_wildcards {
OFPFW_ALL = ((1 << 21) - 1)
};
/* The wildcards for ICMP type and code fields use the transport source
/* The wildcards for ICMP type and code fields use the transport source
* and destination port fields, respectively. */
#define OFPFW_ICMP_TYPE OFPFW_TP_SRC
#define OFPFW_ICMP_CODE OFPFW_TP_DST
@@ -521,7 +521,7 @@ struct ofp_match {
};
OFP_ASSERT(sizeof(struct ofp_match) == 36);
/* The match fields for ICMP type and code use the transport source and
/* The match fields for ICMP type and code use the transport source and
* destination port fields, respectively. */
#define icmp_type tp_src
#define icmp_code tp_dst
@@ -549,16 +549,16 @@ struct ofp_flow_mod {
uint16_t idle_timeout; /* Idle time before discarding (seconds). */
uint16_t hard_timeout; /* Max time before discarding (seconds). */
uint16_t priority; /* Priority level of flow entry. */
uint32_t buffer_id; /* Buffered packet to apply to (or -1).
uint32_t buffer_id; /* Buffered packet to apply to (or -1).
Not meaningful for OFPFC_DELETE*. */
uint16_t out_port; /* For OFPFC_DELETE* commands, require
matching entries to include this as an
output port. A value of OFPP_NONE
matching entries to include this as an
output port. A value of OFPP_NONE
indicates no restriction. */
uint16_t flags; /* One of OFPFF_*. */
uint32_t reserved; /* Reserved for future use. */
struct ofp_action_header actions[0]; /* The action length is inferred
from the length field in the
struct ofp_action_header actions[0]; /* The action length is inferred
from the length field in the
header. */
};
OFP_ASSERT(sizeof(struct ofp_flow_mod) == 64);
@@ -582,7 +582,7 @@ struct ofp_flow_expired {
uint32_t duration; /* Time flow was alive in seconds. */
uint16_t idle_timeout; /* Idle timeout from original flow mod. */
uint8_t pad2[2]; /* Align to 64-bits. */
uint64_t packet_count;
uint64_t packet_count;
uint64_t byte_count;
};
OFP_ASSERT(sizeof(struct ofp_flow_expired) == 72);
@@ -610,13 +610,13 @@ enum ofp_bad_request_code {
OFPBRC_BAD_VERSION, /* ofp_header.version not supported. */
OFPBRC_BAD_TYPE, /* ofp_header.type not supported. */
OFPBRC_BAD_STAT, /* ofp_stats_request.type not supported. */
OFPBRC_BAD_VENDOR, /* Vendor not supported (in ofp_vendor_header
OFPBRC_BAD_VENDOR, /* Vendor not supported (in ofp_vendor_header
* or ofp_stats_request or ofp_stats_reply). */
OFPBRC_BAD_SUBTYPE, /* Vendor subtype not supported. */
OFPBRC_EPERM /* Permissions error. */
};
/* ofp_error_msg 'code' values for OFPET_BAD_ACTION. 'data' contains at least
/* ofp_error_msg 'code' values for OFPET_BAD_ACTION. 'data' contains at least
* the first 64 bytes of the failed request. */
enum ofp_bad_action_code {
OFPBAC_BAD_TYPE, /* Unknown action type. */
@@ -628,11 +628,11 @@ enum ofp_bad_action_code {
OFPBAC_EPERM /* Permissions error. */
};
/* ofp_error_msg 'code' values for OFPET_FLOW_MOD_FAILED. 'data' contains
/* ofp_error_msg 'code' values for OFPET_FLOW_MOD_FAILED. 'data' contains
* at least the first 64 bytes of the failed request. */
enum ofp_flow_mod_failed_code {
OFPFMFC_ALL_TABLES_FULL, /* Flow not added because of full tables. */
OFPFMFC_OVERLAP, /* Attempted to add overlapping flow with
OFPFMFC_OVERLAP, /* Attempted to add overlapping flow with
* CHECK_OVERLAP flag set. */
OFPFMFC_EPERM /* Permissions error. */
};
@@ -643,13 +643,13 @@ struct ofp_error_msg {
uint16_t type;
uint16_t code;
uint8_t data[0]; /* Variable-length data. Interpreted based
uint8_t data[0]; /* Variable-length data. Interpreted based
on the type and code. */
};
OFP_ASSERT(sizeof(struct ofp_error_msg) == 12);
enum ofp_stats_types {
/* Description of this OpenFlow switch.
/* Description of this OpenFlow switch.
* The request body is empty.
* The reply body is struct ofp_desc_stats. */
OFPST_DESC,
@@ -676,7 +676,7 @@ enum ofp_stats_types {
/* Vendor extension.
* The request and reply bodies begin with a 32-bit vendor ID, which takes
* the same form as in "struct ofp_vendor_header". The request and reply
* the same form as in "struct ofp_vendor_header". The request and reply
* bodies are otherwise vendor-defined. */
OFPST_VENDOR = 0xffff
};
@@ -703,7 +703,7 @@ OFP_ASSERT(sizeof(struct ofp_stats_reply) == 12);
#define DESC_STR_LEN 256
#define SERIAL_NUM_LEN 32
/* Body of reply to OFPST_DESC request. Each entry is a NULL-terminated
/* Body of reply to OFPST_DESC request. Each entry is a NULL-terminated
* ASCII string. */
struct ofp_desc_stats {
char mfr_desc[DESC_STR_LEN]; /* Manufacturer description. */
@@ -719,8 +719,8 @@ struct ofp_flow_stats_request {
uint8_t table_id; /* ID of table to read (from ofp_table_stats),
0xff for all tables or 0xfe for emergency. */
uint8_t pad; /* Align to 32 bits. */
uint16_t out_port; /* Require matching entries to include this
as an output port. A value of OFPP_NONE
uint16_t out_port; /* Require matching entries to include this
as an output port. A value of OFPP_NONE
indicates no restriction. */
};
OFP_ASSERT(sizeof(struct ofp_flow_stats_request) == 40);
@@ -749,8 +749,8 @@ struct ofp_aggregate_stats_request {
uint8_t table_id; /* ID of table to read (from ofp_table_stats)
0xff for all tables or 0xfe for emergency. */
uint8_t pad; /* Align to 32 bits. */
uint16_t out_port; /* Require matching entries to include this
as an output port. A value of OFPP_NONE
uint16_t out_port; /* Require matching entries to include this
as an output port. A value of OFPP_NONE
indicates no restriction. */
};
OFP_ASSERT(sizeof(struct ofp_aggregate_stats_request) == 40);
@@ -770,7 +770,7 @@ struct ofp_table_stats {
are consulted first. */
uint8_t pad[3]; /* Align to 32-bits. */
char name[OFP_MAX_TABLE_NAME_LEN];
uint32_t wildcards; /* Bitmap of OFPFW_* wildcards that are
uint32_t wildcards; /* Bitmap of OFPFW_* wildcards that are
supported by the table. */
uint32_t max_entries; /* Max number of entries supported. */
uint32_t active_count; /* Number of active entries. */
@@ -788,20 +788,20 @@ struct ofp_port_stats {
uint64_t tx_packets; /* Number of transmitted packets. */
uint64_t rx_bytes; /* Number of received bytes. */
uint64_t tx_bytes; /* Number of transmitted bytes. */
uint64_t rx_dropped; /* Number of packets dropped by RX. */
uint64_t tx_dropped; /* Number of packets dropped by TX. */
uint64_t rx_dropped; /* Number of packets dropped by RX. */
uint64_t tx_dropped; /* Number of packets dropped by TX. */
uint64_t rx_errors; /* Number of receive errors. This is a super-set
of more specific receive errors and should be
greater than or equal to the sum of all
greater than or equal to the sum of all
rx_*_err values. */
uint64_t tx_errors; /* Number of transmit errors. This is a super-set
of more specific transmit errors and should be
greater than or equal to the sum of all
tx_*_err values (none currently defined.) */
uint64_t rx_frame_err; /* Number of frame alignment errors. */
uint64_t rx_over_err; /* Number of packets with RX overrun. */
uint64_t rx_crc_err; /* Number of CRC errors. */
uint64_t collisions; /* Number of collisions. */
uint64_t rx_frame_err; /* Number of frame alignment errors. */
uint64_t rx_over_err; /* Number of packets with RX overrun. */
uint64_t rx_crc_err; /* Number of CRC errors. */
uint64_t collisions; /* Number of collisions. */
};
OFP_ASSERT(sizeof(struct ofp_port_stats) == 104);
+10
View File
@@ -263,6 +263,10 @@ ofp_print_action(struct ds *string, const struct ofp_action_header *ah,
sizeof(struct ofp_action_nw_addr),
sizeof(struct ofp_action_nw_addr),
},
[OFPAT_SET_NW_TOS] = {
sizeof(struct ofp_action_nw_tos),
sizeof(struct ofp_action_nw_tos),
},
[OFPAT_SET_TP_SRC] = {
sizeof(struct ofp_action_tp_port),
sizeof(struct ofp_action_tp_port),
@@ -363,6 +367,12 @@ ofp_print_action(struct ds *string, const struct ofp_action_header *ah,
break;
}
case OFPAT_SET_NW_TOS: {
struct ofp_action_nw_tos *nt = (struct ofp_action_nw_tos *)ah;
ds_put_format(string, "mod_ip_tos:%d", nt->nw_tos);
break;
}
case OFPAT_SET_TP_SRC: {
struct ofp_action_tp_port *ta = (struct ofp_action_tp_port *)ah;
ds_put_format(string, "mod_tp_src:%d", ntohs(ta->tp_port));
+163 -159
View File
@@ -271,20 +271,19 @@ sub setup_NF2 {
sub setup_user {
setup_pcap_interfaces();
setup_pcap_interfaces();
# create openflow switch on four ports
my $if_string = '';
for (my $i = 5 ; $i <= 7 ; $i++) {
$if_string .= nftest_get_iface("eth$i") . ',';
}
$if_string .= nftest_get_iface("eth8");
# create openflow switch on four ports
my $if_string = '';
for ( my $i = 5 ; $i <= 7 ; $i++ ) {
$if_string .= nftest_get_iface("eth$i") . ',';
}
$if_string .= nftest_get_iface("eth8");
print "about to create ofdatapath` punix:/var/run/test -i $if_string \& \n";
system("${openflow_dir}/udatapath/ofdatapath punix:/var/run/test -i $if_string \&");
print "about to create ofdatapath` punix:/var/run/test -i $if_string \& \n";
system("${openflow_dir}/udatapath/ofdatapath punix:/var/run/test -i $if_string \&");
start_ofprotocol("unix:/var/run/test", @_);
start_ofprotocol("unix:/var/run/test", @_);
}
sub teardown_kmod {
@@ -815,168 +814,173 @@ sub create_flow_mod_from_udp {
}
sub flow_mod_length {
my ( $mod_type, $chg_field ) = @_;
my ($mod_type, $chg_field) = @_;
my $action_length;
if ($mod_type eq 'drop') {
$action_length = 0;
} elsif (defined $chg_field) {
if (($chg_field eq 'dl_src') || ($chg_field eq 'dl_dst')) {
$action_length = $ofp->sizeof('ofp_action_dl_addr') +
$ofp->sizeof('ofp_action_output');
} elsif (($chg_field eq 'nw_src') || ($chg_field eq 'nw_dst')) {
$action_length = $ofp->sizeof('ofp_action_nw_addr') +
$ofp->sizeof('ofp_action_output');
} elsif (($chg_field eq 'tp_src') || ($chg_field eq 'tp_dst')) {
$action_length = $ofp->sizeof('ofp_action_tp_port') +
$ofp->sizeof('ofp_action_output');
} elsif ($chg_field eq 'strip_vlan') {
$action_length = $ofp->sizeof('ofp_action_header') +
$ofp->sizeof('ofp_action_output');
} elsif ($chg_field eq 'vlan_vid') {
$action_length = $ofp->sizeof('ofp_action_vlan_vid') +
$ofp->sizeof('ofp_action_output');
} elsif ($chg_field eq 'vlan_pcp') {
$action_length = $ofp->sizeof('ofp_action_vlan_pcp') +
$ofp->sizeof('ofp_action_output');
} else {
$action_length = $ofp->sizeof('ofp_action_output');
}
my $action_length = 0;
if ($mod_type eq 'drop') {
$action_length = 0;
} elsif (defined $chg_field) {
if (($chg_field eq 'dl_src') || ($chg_field eq 'dl_dst')) {
$action_length = $ofp->sizeof('ofp_action_dl_addr')
+ $ofp->sizeof('ofp_action_output');
} elsif (($chg_field eq 'nw_src') || ($chg_field eq 'nw_dst')) {
$action_length = $ofp->sizeof('ofp_action_nw_addr')
+ $ofp->sizeof('ofp_action_output');
} elsif ($chg_field eq 'nw_tos') {
$action_length = $ofp->sizeof('ofp_action_nw_tos')
+ $ofp->sizeof('ofp_action_output');
} elsif (($chg_field eq 'tp_src') || ($chg_field eq 'tp_dst')) {
$action_length = $ofp->sizeof('ofp_action_tp_port')
+ $ofp->sizeof('ofp_action_output');
} elsif ($chg_field eq 'strip_vlan') {
$action_length = $ofp->sizeof('ofp_action_header')
+ $ofp->sizeof('ofp_action_output');
} elsif ($chg_field eq 'vlan_vid') {
$action_length = $ofp->sizeof('ofp_action_vlan_vid')
+ $ofp->sizeof('ofp_action_output');
} elsif ($chg_field eq 'vlan_pcp') {
$action_length = $ofp->sizeof('ofp_action_vlan_pcp')
+ $ofp->sizeof('ofp_action_output');
} else {
$action_length = $ofp->sizeof('ofp_action_output');
$action_length = $ofp->sizeof('ofp_action_output');
}
my $length = $ofp->sizeof('ofp_flow_mod') + $action_length;
return $length;
} else {
$action_length = $ofp->sizeof('ofp_action_output');
}
my $length = $ofp->sizeof('ofp_flow_mod') + $action_length;
return $length;
}
sub combine_args {
my ($flow_mod, $mod_type, $out_port, $chg_field, $chg_val) = @_;
my ($flow_mod, $mod_type, $out_port, $chg_field, $chg_val) = @_;
my @pad_6 = (0,0,0,0,0,0);
my @pad_4 = (0,0,0,0);
my @pad_3 = (0,0,0);
my @pad_2 = (0,0);
my @pad_6 = (0,0,0,0,0,0);
my @pad_4 = (0,0,0,0);
my @pad_3 = (0,0,0);
my @pad_2 = (0,0);
my $nw_addr_org;
my $ok_org;
my $nw_addr_org;
my $ok_org;
my @dl_addr_org;
my $chg_vlan_pcp_val;
my @dl_addr_org;
my $chg_vlan_pcp_val;
#OUTPUT
#and No action for drops
my $action_output_args;
my $action_output;
if ($mod_type ne 'drop') {
$action_output_args = {
type => $enums{'OFPAT_OUTPUT'},
len => $ofp->sizeof('ofp_action_output'),
port => $out_port,
max_len => 0, # send entire packet
};
$action_output = $ofp->pack( 'ofp_action_output', $action_output_args );
}
#OUTPUT
#and No action for drops
my $action_output_args;
my $action_output;
if ($mod_type ne 'drop') {
$action_output_args = {
type => $enums{'OFPAT_OUTPUT'},
len => $ofp->sizeof('ofp_action_output'),
port => $out_port,
max_len => 0, # send entire packet
};
$action_output = $ofp->pack('ofp_action_output', $action_output_args);
}
#MODIFY ACTION
my $action_mod_args;
my $action_mod;
if (defined $chg_field) {
#SET_DL_SRC
if ($chg_field eq 'dl_src') {
@dl_addr_org = NF2::PDU::get_MAC_address($chg_val);
$action_mod_args = {
type => $enums{'OFPAT_SET_DL_SRC'},
len => $ofp->sizeof('ofp_action_dl_addr'),
dl_addr => \@dl_addr_org,
pad => \@pad_6,
};
$action_mod = $ofp->pack('ofp_action_dl_addr', $action_mod_args);
#SET_DL_DST
} elsif ($chg_field eq 'dl_dst') {
@dl_addr_org = NF2::PDU::get_MAC_address($chg_val);
$action_mod_args = {
type => $enums{'OFPAT_SET_DL_DST'},
len => $ofp->sizeof('ofp_action_dl_addr'),
dl_addr => \@dl_addr_org,
pad => \@pad_6,
};
$action_mod = $ofp->pack('ofp_action_dl_addr', $action_mod_args);
#SET_NW_SRC
} elsif ($chg_field eq 'nw_src') {
($nw_addr_org, $ok_org) = NF2::IP_hdr::getIP($chg_val);
$action_mod_args = {
type => $enums{'OFPAT_SET_NW_SRC'},
len => $ofp->sizeof('ofp_action_nw_addr'),
nw_addr => $nw_addr_org,
};
$action_mod = $ofp->pack('ofp_action_nw_addr', $action_mod_args);
#SET_NW_DST
} elsif ($chg_field eq 'nw_dst') {
($nw_addr_org, $ok_org) = NF2::IP_hdr::getIP($chg_val);
$action_mod_args = {
type => $enums{'OFPAT_SET_NW_DST'},
len => $ofp->sizeof('ofp_action_nw_addr'),
nw_addr => $nw_addr_org,
};
$action_mod = $ofp->pack('ofp_action_nw_addr', $action_mod_args);
#SET_TP_SRC
} elsif ($chg_field eq 'tp_src') {
$action_mod_args = {
type => $enums{'OFPAT_SET_TP_SRC'},
len => $ofp->sizeof('ofp_action_tp_port'),
tp_port => $chg_val,
pad => \@pad_2,
};
$action_mod = $ofp->pack('ofp_action_tp_port', $action_mod_args);
#SET_TP_DST
} elsif ($chg_field eq 'tp_dst') {
$action_mod_args = {
type => $enums{'OFPAT_SET_TP_DST'},
len => $ofp->sizeof('ofp_action_tp_port'),
tp_port => $chg_val,
pad => \@pad_2,
};
$action_mod = $ofp->pack('ofp_action_tp_port', $action_mod_args);
#STRIP_VLAN
} elsif ($chg_field eq 'strip_vlan') {
$action_mod_args = {
type => $enums{'OFPAT_STRIP_VLAN'},
len => $ofp->sizeof('ofp_action_header'),
pad => \@pad_4,
};
$action_mod = $ofp->pack('ofp_action_header', $action_mod_args);
#SET_VLAN_VID
} elsif ($chg_field eq 'vlan_vid') {
$action_mod_args = {
type => $enums{'OFPAT_SET_VLAN_VID'},
len => $ofp->sizeof('ofp_action_vlan_vid'),
vlan_vid => $chg_val,
pad => \@pad_2,
};
$action_mod = $ofp->pack('ofp_action_vlan_vid', $action_mod_args);
#SET_VLAN_PCP
} elsif ($chg_field eq 'vlan_pcp') {
$chg_vlan_pcp_val = ($chg_val>>13) & 0x0007;
$action_mod_args = {
type => $enums{'OFPAT_SET_VLAN_PCP'},
len => $ofp->sizeof('ofp_action_vlan_pcp'),
vlan_pcp => $chg_vlan_pcp_val,
pad => \@pad_3,
};
$action_mod = $ofp->pack('ofp_action_vlan_pcp', $action_mod_args);
} else {
$action_mod = undef;
}
#MODIFY ACTION
my $action_mod_args;
my $action_mod;
if (defined $chg_field) {
if ($chg_field eq 'dl_src') { #SET_DL_SRC
@dl_addr_org = NF2::PDU::get_MAC_address($chg_val);
$action_mod_args = {
type => $enums{'OFPAT_SET_DL_SRC'},
len => $ofp->sizeof('ofp_action_dl_addr'),
dl_addr => \@dl_addr_org,
pad => \@pad_6,
};
$action_mod = $ofp->pack('ofp_action_dl_addr', $action_mod_args);
} elsif ($chg_field eq 'dl_dst') { #SET_DL_DST
@dl_addr_org = NF2::PDU::get_MAC_address($chg_val);
$action_mod_args = {
type => $enums{'OFPAT_SET_DL_DST'},
len => $ofp->sizeof('ofp_action_dl_addr'),
dl_addr => \@dl_addr_org,
pad => \@pad_6,
};
$action_mod = $ofp->pack('ofp_action_dl_addr', $action_mod_args);
} elsif ($chg_field eq 'nw_src') { #SET_NW_SRC
($nw_addr_org, $ok_org) = NF2::IP_hdr::getIP($chg_val);
$action_mod_args = {
type => $enums{'OFPAT_SET_NW_SRC'},
len => $ofp->sizeof('ofp_action_nw_addr'),
nw_addr => $nw_addr_org,
};
$action_mod = $ofp->pack('ofp_action_nw_addr', $action_mod_args);
} elsif ($chg_field eq 'nw_dst') { #SET_NW_DST
($nw_addr_org, $ok_org) = NF2::IP_hdr::getIP($chg_val);
$action_mod_args = {
type => $enums{'OFPAT_SET_NW_DST'},
len => $ofp->sizeof('ofp_action_nw_addr'),
nw_addr => $nw_addr_org,
};
$action_mod = $ofp->pack('ofp_action_nw_addr', $action_mod_args);
} elsif ($chg_field eq 'nw_tos') { #SET_NW_TOS
$action_mod_args = {
type => $enums{'OFPAT_SET_NW_TOS'},
len => $ofp->sizeof('ofp_action_nw_tos'),
nw_tos => $chg_val,
pad => \@pad_3,
};
$action_mod = $ofp->pack('ofp_action_nw_tos', $action_mod_args);
} elsif ($chg_field eq 'tp_src') { #SET_TP_SRC
$action_mod_args = {
type => $enums{'OFPAT_SET_TP_SRC'},
len => $ofp->sizeof('ofp_action_tp_port'),
tp_port => $chg_val,
pad => \@pad_2,
};
$action_mod = $ofp->pack('ofp_action_tp_port', $action_mod_args);
} elsif ($chg_field eq 'tp_dst') { #SET_TP_DST
$action_mod_args = {
type => $enums{'OFPAT_SET_TP_DST'},
len => $ofp->sizeof('ofp_action_tp_port'),
tp_port => $chg_val,
pad => \@pad_2,
};
$action_mod = $ofp->pack('ofp_action_tp_port', $action_mod_args);
} elsif ($chg_field eq 'strip_vlan') { #STRIP_VLAN
$action_mod_args = {
type => $enums{'OFPAT_STRIP_VLAN'},
len => $ofp->sizeof('ofp_action_header'),
pad => \@pad_4,
};
$action_mod = $ofp->pack('ofp_action_header', $action_mod_args);
} elsif ($chg_field eq 'vlan_vid') { #SET_VLAN_VID
$action_mod_args = {
type => $enums{'OFPAT_SET_VLAN_VID'},
len => $ofp->sizeof('ofp_action_vlan_vid'),
vlan_vid => $chg_val,
pad => \@pad_2,
};
$action_mod = $ofp->pack('ofp_action_vlan_vid', $action_mod_args);
} elsif ($chg_field eq 'vlan_pcp') { #SET_VLAN_PCP
$chg_vlan_pcp_val = ($chg_val>>13) & 0x0007;
$action_mod_args = {
type => $enums{'OFPAT_SET_VLAN_PCP'},
len => $ofp->sizeof('ofp_action_vlan_pcp'),
vlan_pcp => $chg_vlan_pcp_val,
pad => \@pad_3,
};
$action_mod = $ofp->pack('ofp_action_vlan_pcp', $action_mod_args);
} else {
$action_mod = undef;
$action_mod = undef;
}
} else {
$action_mod = undef;
}
if (defined $action_mod) {
$flow_mod_pkt = $flow_mod . $action_mod . $action_output;
} else {
$flow_mod_pkt = $flow_mod . $action_output;
}
return $flow_mod_pkt;
if (defined $action_mod) {
$flow_mod_pkt = $flow_mod . $action_mod . $action_output;
} else {
$flow_mod_pkt = $flow_mod . $action_output;
}
return $flow_mod_pkt;
}
sub create_flow_mod_from_udp_action {
+95
View File
@@ -0,0 +1,95 @@
#!/usr/bin/perl -w
# test_set_nw_dst
use strict;
use OF::Includes;
sub send_expect_exact {
my ($ofp, $sock, $options_ref, $in_port_offset, $out_port_offset, $max_idle, $pkt_len) = @_;
my $in_port = $in_port_offset + $$options_ref{'port_base'};
my $out_port = $out_port_offset + $$options_ref{'port_base'};
# in_port refers to the flow mod entry's input
# Create the payload ourselves to make sure the two packets match
# Jean II
my $pkt_payload = [map {int(rand(256))} (1..($pkt_len - 8 - 4 - 16 - 14))];
# This is the packet we are sending... - Jean II
my $test_pkt_args = {
DA => "00:00:00:00:00:0" . ($out_port + 1),
SA => "00:00:00:00:00:0" . ($in_port + 1),
src_ip => "192.168.200." . ($in_port + 1),
dst_ip => "192.168.201." . ($out_port + 1),
ttl => 64,
len => $pkt_len,
src_port => 1,
dst_port => 0,
data => $pkt_payload
};
my $test_pkt = new NF2::UDP_pkt(%$test_pkt_args);
# This is the packet we are expecting to receive - Jean II
my $expect_pkt_args = {
DA => "00:00:00:00:00:0" . ($out_port + 1),
SA => "00:00:00:00:00:0" . ($in_port + 1),
src_ip => "192.168.200." . ($in_port + 1),
dst_ip => ($out_port + 1) . ".201.168.192",
ttl => 64,
len => $pkt_len,
src_port => 1,
dst_port => 0,
data => $pkt_payload
};
my $expect_pkt = new NF2::UDP_pkt(%$expect_pkt_args);
#print HexDump ($test_pkt->packed);
my $wildcards = 0x0; # exact match
my $flags = $enums{'OFPFF_SEND_FLOW_EXP'}; # want flow expiry
# Get to the IP address in the expected packet - Jean II
my $ref_to_ip_hdr = ( $expect_pkt->{'IP_hdr'} );
my $ip_hdr_bytes = $$ref_to_ip_hdr->{'bytes'};
my @dst_ip_subarray = @{$ip_hdr_bytes}[ 16 .. 19 ];
my $dst_ip_inverted = ((2**24) * $dst_ip_subarray[0]
+ (2**16) * $dst_ip_subarray[1]
+ (2**8) * $dst_ip_subarray[2]
+ $dst_ip_subarray[3]);
my $flow_mod_pkt = create_flow_mod_from_udp_action($ofp, $test_pkt, $in_port, $out_port, $max_idle, $flags, $wildcards, 'OFPFC_ADD', 'nw_dst', $dst_ip_inverted);
#print HexDump($flow_mod_pkt);
# Send 'flow_mod' message
print $sock $flow_mod_pkt;
print "sent flow_mod message\n";
# Give OF switch time to process the flow mod
usleep($$options_ref{'send_delay'});
# Send a packet - ensure packet comes out desired port
nftest_send("eth" . ($in_port_offset + 1), $test_pkt->packed);
nftest_expect("eth" . ($out_port_offset + 1), $expect_pkt->packed);
}
sub test_set_nw_dst {
my ($ofp, $sock, $options_ref, $i, $j, $wildcards) = @_;
my $max_idle = $$options_ref{'max_idle'};
my $pkt_len = $$options_ref{'pkt_len'};
my $pkt_total = $$options_ref{'pkt_total'};
send_expect_exact($ofp, $sock, $options_ref, $i, $j, $max_idle, $pkt_len);
wait_for_flow_expired($ofp, $sock, $options_ref, $pkt_len, $pkt_total);
}
sub my_test {
my ($sock, $options_ref) = @_;
# send from every port to every other port
for_all_port_pairs($ofp, $sock, $options_ref, \&test_set_nw_dst, 0x0);
}
run_black_box_test(\&my_test, \@ARGV);
+89
View File
@@ -0,0 +1,89 @@
#!/usr/bin/perl -w
# test_set_nw_tos
use strict;
use OF::Includes;
sub send_expect_exact {
my ($ofp, $sock, $options_ref, $in_port_offset, $out_port_offset, $max_idle, $pkt_len) = @_;
my $in_port = $in_port_offset + $$options_ref{'port_base'};
my $out_port = $out_port_offset + $$options_ref{'port_base'};
# in_port refers to the flow mod entry's input
# Create the payload ourselves to make sure the two packets match
# Jean II
my $pkt_payload = [map {int(rand(256))} (1..($pkt_len - 8 - 4 - 16 - 14))];
# This is the packet we are sending... - Jean II
my $test_pkt_args = {
DA => "00:00:00:00:00:0" . ($out_port + 1),
SA => "00:00:00:00:00:0" . ($in_port + 1),
src_ip => "192.168.200." . ($in_port + 1),
dst_ip => "192.168.201." . ($out_port + 1),
tos => 0xa9,
ttl => 64,
len => $pkt_len,
src_port => 1,
dst_port => 0,
data => $pkt_payload
};
my $test_pkt = new NF2::UDP_pkt(%$test_pkt_args);
# This is the packet we are expecting to receive - Jean II
my $expect_pkt_args = {
DA => "00:00:00:00:00:0" . ($out_port + 1),
SA => "00:00:00:00:00:0" . ($in_port + 1),
src_ip => "192.168.200." . ($in_port + 1),
dst_ip => "192.168.201." . ($out_port + 1),
tos => 0x55,
ttl => 64,
len => $pkt_len,
src_port => 1,
dst_port => 0,
data => $pkt_payload
};
my $expect_pkt = new NF2::UDP_pkt(%$expect_pkt_args);
#print HexDump ($test_pkt->packed);
my $wildcards = 0x0; # exact match
my $flags = $enums{'OFPFF_SEND_FLOW_EXP'}; # want flow expiry
my $nw_tos = 0x56;
my $flow_mod_pkt = create_flow_mod_from_udp_action($ofp, $test_pkt, $in_port, $out_port, $max_idle, $flags, $wildcards, 'OFPFC_ADD', 'nw_tos', $nw_tos);
#print HexDump($flow_mod_pkt);
# Send 'flow_mod' message
print $sock $flow_mod_pkt;
print "sent flow_mod message\n";
# Give OF switch time to process the flow mod
usleep($$options_ref{'send_delay'});
# Send a packet - ensure packet comes out desired port
nftest_send("eth" . ($in_port_offset + 1), $test_pkt->packed);
nftest_expect("eth" . ($out_port_offset + 1), $expect_pkt->packed);
}
sub test_set_nw_tos {
my ($ofp, $sock, $options_ref, $i, $j, $wildcards) = @_;
my $max_idle = $$options_ref{'max_idle'};
my $pkt_len = $$options_ref{'pkt_len'};
my $pkt_total = $$options_ref{'pkt_total'};
send_expect_exact($ofp, $sock, $options_ref, $i, $j, $max_idle, $pkt_len);
wait_for_flow_expired($ofp, $sock, $options_ref, $pkt_len, $pkt_total);
}
sub my_test {
my ($sock, $options_ref) = @_;
# send from every port to every other port
for_all_port_pairs( $ofp, $sock, $options_ref, \&test_set_nw_tos, 0x0);
}
run_black_box_test(\&my_test, \@ARGV);
@@ -34,6 +34,8 @@ test_drop_exact/run.pl
test_forward_exact_modify_action/run.pl
test_forward_wildcard_modify_action/run.pl
test_flow_mod_check/run.pl
test_set_nw_dst/run.pl
test_set_nw_tos/run.pl
## ICMP handling Tests
test_forward_exact_icmp_port/run.pl
+33
View File
@@ -197,6 +197,33 @@ set_nw_addr(struct ofpbuf *buffer, struct sw_flow_key *key,
}
}
static void
set_nw_tos(struct ofpbuf *buffer, struct sw_flow_key *key,
const struct ofp_action_header *ah)
{
struct ofp_action_nw_tos *nt = (struct ofp_action_nw_tos *)ah;
uint16_t eth_proto = ntohs(key->flow.dl_type);
if (eth_proto == ETH_TYPE_IP) {
struct ip_header *nh = buffer->l3;
uint8_t new, *field;
/* JeanII : Set only 6 bits, don't clobber ECN */
new = (nt->nw_tos & 0xFC) | (nh->ip_tos & 0x03);
/* Get address of field */
field = &nh->ip_tos;
/* jklee : ip tos field is not included in TCP pseudo header.
* Need magic as update_csum() don't work with 8 bits. */
nh->ip_csum = recalc_csum32(nh->ip_csum, htons((uint16_t)*field),
htons((uint16_t)new));
/* Change the IP ToS bits */
*field = new;
}
}
static void
set_tp_port(struct ofpbuf *buffer, struct sw_flow_key *key,
const struct ofp_action_header *ah)
@@ -283,6 +310,12 @@ static const struct openflow_action of_actions[] = {
NULL,
set_nw_addr
},
[OFPAT_SET_NW_TOS] = {
sizeof(struct ofp_action_nw_tos),
sizeof(struct ofp_action_nw_tos),
NULL,
set_nw_tos
},
[OFPAT_SET_TP_SRC] = {
sizeof(struct ofp_action_tp_port),
sizeof(struct ofp_action_tp_port),
+3
View File
@@ -410,6 +410,9 @@ Modifies the destination mac address on a packet, e.g., actions=mod_dl_dst:12:34
.IP \fBmod_dl_src\fR:\fIsrc_mac\fR
Modifies the source mac address on a packet, e.g., actions=mod_dl_src:12:34:56:78:9a:bc
.IP \fBmod_nw_tos\fR:\fItos/dscp\fR
Modifies the ToS/DSCP (only 6-bits, not modify reserved 2-bits for future use) field of IPv4 header on a packet.
.IP \fBstrip_vlan\fR
Strips the VLAN tag from a packet if it is present.
.RE
+6 -3
View File
@@ -694,9 +694,8 @@ do_dump_tables(const struct settings *s UNUSED, int argc UNUSED, char *argv[])
dump_trivial_stats_transaction(argv[1], OFPST_TABLE);
}
static uint32_t
str_to_u32(const char *str)
str_to_u32(const char *str)
{
char *tail;
uint32_t value;
@@ -806,7 +805,11 @@ str_to_action(char *str, struct ofpbuf *b)
arg++;
}
if (!strcasecmp(act, "mod_vlan_vid")) {
if (!strcasecmp(act, "mod_nw_tos")) {
struct ofp_action_nw_tos *va;
va = put_action(b, sizeof *va, OFPAT_SET_NW_TOS);
va->nw_tos = str_to_u32(arg);
} else if (!strcasecmp(act, "mod_vlan_vid")) {
struct ofp_action_vlan_vid *va;
va = put_action(b, sizeof *va, OFPAT_SET_VLAN_VID);
va->vlan_vid = htons(str_to_u32(arg));
@@ -99,12 +99,13 @@ static const value_string names_ofp_action_type[] = {
{ OFPAT_SET_DL_DST, "Ethernet destination address" },
{ OFPAT_SET_NW_SRC, "IP source address" },
{ OFPAT_SET_NW_DST, "IP destination address" },
{ OFPAT_SET_NW_TOS, "Set IP TOS field" },
{ OFPAT_SET_TP_SRC, "TCP/UDP source port" },
{ OFPAT_SET_TP_DST, "TCP/UDP destination port"},
{ OFPAT_VENDOR, "Vendor-defined action"},
{ 0, NULL }
};
#define NUM_ACTIONS_FLAGS 10
#define NUM_ACTIONS_FLAGS 11
#define NUM_PORT_CONFIG_FLAGS 7
#define NUM_PORT_STATE_FLAGS 1
#define NUM_PORT_FEATURES_FLAGS 12
@@ -414,6 +415,7 @@ static gint ofp_action_vlan_vid = -1;
static gint ofp_action_vlan_pcp = -1;
static gint ofp_action_dl_addr = -1;
static gint ofp_action_nw_addr = -1;
static gint ofp_action_nw_tos = -1;
static gint ofp_action_tp_port = -1;
static gint ofp_action_vendor = -1;
static gint ofp_action_unknown = -1;
@@ -1076,6 +1078,9 @@ void proto_register_openflow()
{ &ofp_action_nw_addr,
{ "IP Addr", "of.action_nw_addr", FT_IPv4, BASE_NONE, NO_STRINGS, NO_MASK, "IP Addr", HFILL }},
{ &ofp_action_nw_tos,
{ "IP TOS bits", "of.action_vlan_pcp", FT_UINT8, BASE_DEC, NO_STRINGS, NO_MASK, "IP TOS bits", HFILL }},
{ &ofp_action_tp_port,
{ "Port", "of.action_tp_port", FT_UINT16, BASE_DEC, NO_STRINGS, NO_MASK, "TCP/UDP Port", HFILL }},
@@ -1169,9 +1174,12 @@ void proto_register_openflow()
{ " IP destination address", "of.sf_actions_ip_dst_addr", FT_UINT32, BASE_DEC, VALS(names_choice), 1 << OFPAT_SET_NW_DST, "IP destination address", HFILL }},
{ &ofp_switch_features_actions[8],
{ " TCP/UDP source", "of.sf_actions_src_port", FT_UINT32, BASE_DEC, VALS(names_choice), 1 << OFPAT_SET_TP_SRC, "TCP/UDP source port", HFILL }},
{ " Set IP TOS bits", "of.sf_actions_ip_tos", FT_UINT32, BASE_DEC, VALS(names_choice), 1 << OFPAT_SET_NW_TOS, "Set IP TOS bits", HFILL }},
{ &ofp_switch_features_actions[9],
{ " TCP/UDP source", "of.sf_actions_src_port", FT_UINT32, BASE_DEC, VALS(names_choice), 1 << OFPAT_SET_TP_SRC, "TCP/UDP source port", HFILL }},
{ &ofp_switch_features_actions[10],
{ " TCP/UDP destination", "of.sf_actions_dst_port", FT_UINT32, BASE_DEC, VALS(names_choice), 1 << OFPAT_SET_TP_DST, "TCP/UDP destination port", HFILL }},
{ &ofp_switch_features_ports_hdr,
@@ -2221,6 +2229,11 @@ static gint dissect_action(proto_tree* tree, proto_item* item, tvbuff_t *tvb, pa
add_child( action_tree, ofp_action_nw_addr, tvb, offset, 4 );
break;
case OFPAT_SET_NW_TOS:
add_child( action_tree, ofp_action_nw_tos, tvb, offset, 1);
dissect_pad(action_tree, offset, 3);
break;
case OFPAT_SET_TP_SRC:
case OFPAT_SET_TP_DST:
add_child( action_tree, ofp_action_tp_port, tvb, offset, 2 );