2
0
mirror of https://github.com/openvswitch/ovs synced 2025-08-22 18:07:40 +00:00

Support matching and modifying IP ECN bits.

Signed-off-by: Justin Pettit <jpettit@nicira.com>
Acked-by: Jesse Gross <jesse@nicira.com>
This commit is contained in:
Justin Pettit 2011-11-02 23:34:15 -07:00
parent 9e44d71563
commit 530180fd5a
21 changed files with 146 additions and 72 deletions

2
NEWS
View File

@ -2,6 +2,8 @@ post-v1.3.0
------------------------ ------------------------
- OpenFlow: - OpenFlow:
- Added ability to match on IPv6 flow label through NXM. - Added ability to match on IPv6 flow label through NXM.
- Added ability to match on ECN bits in IPv4 and IPv6 through NXM.
- Added ability to modify ECN bits in IPv4.
- ovs-appctl: - ovs-appctl:
- New "fdb/flush" command to flush bridge's MAC learning table. - New "fdb/flush" command to flush bridge's MAC learning table.

View File

@ -19,9 +19,9 @@
#include <linux/in6.h> #include <linux/in6.h>
#include <linux/if_arp.h> #include <linux/if_arp.h>
#include <linux/if_vlan.h> #include <linux/if_vlan.h>
#include <net/inet_ecn.h>
#include <net/ip.h> #include <net/ip.h>
#include <net/checksum.h> #include <net/checksum.h>
#include <net/dsfield.h>
#include "actions.h" #include "actions.h"
#include "checksum.h" #include "checksum.h"
@ -151,17 +151,6 @@ static void set_ip_addr(struct sk_buff *skb, struct iphdr *nh,
*addr = new_addr; *addr = new_addr;
} }
static void set_ip_tos(struct sk_buff *skb, struct iphdr *nh, u8 new_tos)
{
u8 old, new;
/* Set the DSCP bits and preserve the ECN bits. */
old = nh->tos;
new = new_tos | (nh->tos & INET_ECN_MASK);
csum_replace2(&nh->check, htons(old), htons(new));
nh->tos = new;
}
static int set_ipv4(struct sk_buff *skb, const struct ovs_key_ipv4 *ipv4_key) static int set_ipv4(struct sk_buff *skb, const struct ovs_key_ipv4 *ipv4_key)
{ {
struct iphdr *nh; struct iphdr *nh;
@ -181,7 +170,7 @@ static int set_ipv4(struct sk_buff *skb, const struct ovs_key_ipv4 *ipv4_key)
set_ip_addr(skb, nh, &nh->daddr, ipv4_key->ipv4_dst); set_ip_addr(skb, nh, &nh->daddr, ipv4_key->ipv4_dst);
if (ipv4_key->ipv4_tos != nh->tos) if (ipv4_key->ipv4_tos != nh->tos)
set_ip_tos(skb, nh, ipv4_key->ipv4_tos); ipv4_change_dsfield(nh, 0, ipv4_key->ipv4_tos);
return 0; return 0;
} }

View File

@ -41,7 +41,6 @@
#include <linux/openvswitch.h> #include <linux/openvswitch.h>
#include <linux/rculist.h> #include <linux/rculist.h>
#include <linux/dmi.h> #include <linux/dmi.h>
#include <net/inet_ecn.h>
#include <net/genetlink.h> #include <net/genetlink.h>
#include "checksum.h" #include "checksum.h"
@ -589,9 +588,6 @@ static int validate_action_key(const struct nlattr *a,
if (ipv4_key->ipv4_proto != flow_key->ip.proto) if (ipv4_key->ipv4_proto != flow_key->ip.proto)
return -EINVAL; return -EINVAL;
if (ipv4_key->ipv4_tos & INET_ECN_MASK)
return -EINVAL;
if (ipv4_key->ipv4_frag != flow_key->ip.frag) if (ipv4_key->ipv4_frag != flow_key->ip.frag)
return -EINVAL; return -EINVAL;

View File

@ -30,7 +30,6 @@
#include <linux/icmp.h> #include <linux/icmp.h>
#include <linux/icmpv6.h> #include <linux/icmpv6.h>
#include <linux/rculist.h> #include <linux/rculist.h>
#include <net/inet_ecn.h>
#include <net/ip.h> #include <net/ip.h>
#include <net/ipv6.h> #include <net/ipv6.h>
#include <net/ndisc.h> #include <net/ndisc.h>
@ -200,7 +199,7 @@ static int parse_ipv6hdr(struct sk_buff *skb, struct sw_flow_key *key,
payload_ofs = (u8 *)(nh + 1) - skb->data; payload_ofs = (u8 *)(nh + 1) - skb->data;
key->ip.proto = NEXTHDR_NONE; key->ip.proto = NEXTHDR_NONE;
key->ip.tos = ipv6_get_dsfield(nh) & ~INET_ECN_MASK; key->ip.tos = ipv6_get_dsfield(nh);
key->ipv6.label = *(__be32 *)nh & htonl(IPV6_FLOWINFO_FLOWLABEL); key->ipv6.label = *(__be32 *)nh & htonl(IPV6_FLOWINFO_FLOWLABEL);
ipv6_addr_copy(&key->ipv6.addr.src, &nh->saddr); ipv6_addr_copy(&key->ipv6.addr.src, &nh->saddr);
ipv6_addr_copy(&key->ipv6.addr.dst, &nh->daddr); ipv6_addr_copy(&key->ipv6.addr.dst, &nh->daddr);
@ -689,7 +688,7 @@ int flow_extract(struct sk_buff *skb, u16 in_port, struct sw_flow_key *key,
key->ipv4.addr.dst = nh->daddr; key->ipv4.addr.dst = nh->daddr;
key->ip.proto = nh->protocol; key->ip.proto = nh->protocol;
key->ip.tos = nh->tos & ~INET_ECN_MASK; key->ip.tos = nh->tos;
offset = nh->frag_off & htons(IP_OFFSET); offset = nh->frag_off & htons(IP_OFFSET);
if (offset) { if (offset) {
@ -958,8 +957,6 @@ int flow_from_nlattrs(struct sw_flow_key *swkey, int *key_lenp,
if (swkey->eth.type != htons(ETH_P_IP)) if (swkey->eth.type != htons(ETH_P_IP))
goto invalid; goto invalid;
ipv4_key = nla_data(nla); ipv4_key = nla_data(nla);
if (ipv4_key->ipv4_tos & INET_ECN_MASK)
goto invalid;
if (ipv4_key->ipv4_frag > OVS_FRAG_TYPE_MAX) if (ipv4_key->ipv4_frag > OVS_FRAG_TYPE_MAX)
goto invalid; goto invalid;
swkey->ip.proto = ipv4_key->ipv4_proto; swkey->ip.proto = ipv4_key->ipv4_proto;
@ -974,8 +971,6 @@ int flow_from_nlattrs(struct sw_flow_key *swkey, int *key_lenp,
if (swkey->eth.type != htons(ETH_P_IPV6)) if (swkey->eth.type != htons(ETH_P_IPV6))
goto invalid; goto invalid;
ipv6_key = nla_data(nla); ipv6_key = nla_data(nla);
if (ipv6_key->ipv6_tos & INET_ECN_MASK)
goto invalid;
if (ipv6_key->ipv6_frag > OVS_FRAG_TYPE_MAX) if (ipv6_key->ipv6_frag > OVS_FRAG_TYPE_MAX)
goto invalid; goto invalid;
swkey->ipv6.label = ipv6_key->ipv6_label; swkey->ipv6.label = ipv6_key->ipv6_label;
@ -1249,7 +1244,7 @@ int flow_to_nlattrs(const struct sw_flow_key *swkey, struct sk_buff *skb)
ipv4_key->ipv4_src = swkey->ipv4.addr.src; ipv4_key->ipv4_src = swkey->ipv4.addr.src;
ipv4_key->ipv4_dst = swkey->ipv4.addr.dst; ipv4_key->ipv4_dst = swkey->ipv4.addr.dst;
ipv4_key->ipv4_proto = swkey->ip.proto; ipv4_key->ipv4_proto = swkey->ip.proto;
ipv4_key->ipv4_tos = swkey->ip.tos & ~INET_ECN_MASK; ipv4_key->ipv4_tos = swkey->ip.tos;
ipv4_key->ipv4_frag = swkey->ip.frag; ipv4_key->ipv4_frag = swkey->ip.frag;
} else if (swkey->eth.type == htons(ETH_P_IPV6)) { } else if (swkey->eth.type == htons(ETH_P_IPV6)) {
struct ovs_key_ipv6 *ipv6_key; struct ovs_key_ipv6 *ipv6_key;
@ -1265,7 +1260,7 @@ int flow_to_nlattrs(const struct sw_flow_key *swkey, struct sk_buff *skb)
sizeof(ipv6_key->ipv6_dst)); sizeof(ipv6_key->ipv6_dst));
ipv6_key->ipv6_label = swkey->ipv6.label; ipv6_key->ipv6_label = swkey->ipv6.label;
ipv6_key->ipv6_proto = swkey->ip.proto; ipv6_key->ipv6_proto = swkey->ip.proto;
ipv6_key->ipv6_tos = swkey->ip.tos & ~INET_ECN_MASK; ipv6_key->ipv6_tos = swkey->ip.tos;
ipv6_key->ipv6_frag = swkey->ip.frag; ipv6_key->ipv6_frag = swkey->ip.frag;
} else if (swkey->eth.type == htons(ETH_P_ARP)) { } else if (swkey->eth.type == htons(ETH_P_ARP)) {
struct ovs_key_arp *arp_key; struct ovs_key_arp *arp_key;

View File

@ -44,7 +44,7 @@ struct sw_flow_key {
} eth; } eth;
struct { struct {
u8 proto; /* IP protocol or lower 8 bits of ARP opcode. */ u8 proto; /* IP protocol or lower 8 bits of ARP opcode. */
u8 tos; /* IP ToS DSCP in high 6 bits. */ u8 tos; /* IP ToS. */
u8 frag; /* One of OVS_FRAG_TYPE_*. */ u8 frag; /* One of OVS_FRAG_TYPE_*. */
} ip; } ip;
union { union {

View File

@ -1623,6 +1623,15 @@ OFP_ASSERT(sizeof(struct nx_action_output_reg) == 24);
* Masking: Not maskable. */ * Masking: Not maskable. */
#define NXM_NX_IPV6_LABEL NXM_HEADER (0x0001, 27, 4) #define NXM_NX_IPV6_LABEL NXM_HEADER (0x0001, 27, 4)
/* The ECN of the IP header.
*
* Prereqs: NXM_OF_ETH_TYPE must be either 0x0800 or 0x86dd.
*
* Format: ECN in the low-order 2 bits.
*
* Masking: Not maskable. */
#define NXM_NX_IP_ECN NXM_HEADER (0x0001, 28, 1)
/* ## --------------------- ## */ /* ## --------------------- ## */
/* ## Requests and replies. ## */ /* ## Requests and replies. ## */
/* ## --------------------- ## */ /* ## --------------------- ## */

View File

@ -318,11 +318,19 @@ cls_rule_set_nw_dst_masked(struct cls_rule *rule, ovs_be32 ip, ovs_be32 mask)
} }
void void
cls_rule_set_nw_tos(struct cls_rule *rule, uint8_t nw_tos) cls_rule_set_nw_dscp(struct cls_rule *rule, uint8_t nw_dscp)
{ {
rule->wc.tos_mask |= IP_DSCP_MASK; rule->wc.tos_mask |= IP_DSCP_MASK;
rule->flow.tos &= ~IP_DSCP_MASK; rule->flow.tos &= ~IP_DSCP_MASK;
rule->flow.tos |= nw_tos & IP_DSCP_MASK; rule->flow.tos |= nw_dscp & IP_DSCP_MASK;
}
void
cls_rule_set_nw_ecn(struct cls_rule *rule, uint8_t nw_ecn)
{
rule->wc.tos_mask |= IP_ECN_MASK;
rule->flow.tos &= ~IP_ECN_MASK;
rule->flow.tos |= nw_ecn & IP_ECN_MASK;
} }
void void
@ -620,6 +628,9 @@ cls_rule_format(const struct cls_rule *rule, struct ds *s)
if (wc->tos_mask & IP_DSCP_MASK) { if (wc->tos_mask & IP_DSCP_MASK) {
ds_put_format(s, "nw_tos=%"PRIu8",", f->tos & IP_DSCP_MASK); ds_put_format(s, "nw_tos=%"PRIu8",", f->tos & IP_DSCP_MASK);
} }
if (wc->tos_mask & IP_ECN_MASK) {
ds_put_format(s, "nw_ecn=%"PRIu8",", f->tos & IP_ECN_MASK);
}
switch (wc->frag_mask) { switch (wc->frag_mask) {
case FLOW_FRAG_ANY | FLOW_FRAG_LATER: case FLOW_FRAG_ANY | FLOW_FRAG_LATER:
ds_put_format(s, "frag=%s,", ds_put_format(s, "frag=%s,",

View File

@ -116,7 +116,8 @@ void cls_rule_set_nw_src(struct cls_rule *, ovs_be32);
bool cls_rule_set_nw_src_masked(struct cls_rule *, ovs_be32 ip, ovs_be32 mask); bool cls_rule_set_nw_src_masked(struct cls_rule *, ovs_be32 ip, ovs_be32 mask);
void cls_rule_set_nw_dst(struct cls_rule *, ovs_be32); void cls_rule_set_nw_dst(struct cls_rule *, ovs_be32);
bool cls_rule_set_nw_dst_masked(struct cls_rule *, ovs_be32 ip, ovs_be32 mask); bool cls_rule_set_nw_dst_masked(struct cls_rule *, ovs_be32 ip, ovs_be32 mask);
void cls_rule_set_nw_tos(struct cls_rule *, uint8_t); void cls_rule_set_nw_dscp(struct cls_rule *, uint8_t);
void cls_rule_set_nw_ecn(struct cls_rule *, uint8_t);
void cls_rule_set_frag(struct cls_rule *, uint8_t frag); void cls_rule_set_frag(struct cls_rule *, uint8_t frag);
void cls_rule_set_frag_masked(struct cls_rule *, uint8_t frag, uint8_t mask); void cls_rule_set_frag_masked(struct cls_rule *, uint8_t frag, uint8_t mask);
void cls_rule_set_icmp_type(struct cls_rule *, uint8_t); void cls_rule_set_icmp_type(struct cls_rule *, uint8_t);

View File

@ -1086,12 +1086,9 @@ dp_netdev_set_ip_tos(struct ip_header *nh, uint8_t new_tos)
{ {
uint8_t *field = &nh->ip_tos; uint8_t *field = &nh->ip_tos;
/* Set the DSCP bits and preserve the ECN bits. */
uint8_t new = new_tos | (nh->ip_tos & IP_ECN_MASK);
nh->ip_csum = recalc_csum16(nh->ip_csum, htons((uint16_t)*field), nh->ip_csum = recalc_csum16(nh->ip_csum, htons((uint16_t)*field),
htons((uint16_t) new)); htons((uint16_t) new_tos));
*field = new; *field = new_tos;
} }
static void static void

View File

@ -148,7 +148,7 @@ parse_ipv6(struct ofpbuf *packet, struct flow *flow)
flow->ipv6_dst = nh->ip6_dst; flow->ipv6_dst = nh->ip6_dst;
tc_flow = get_unaligned_be32(&nh->ip6_flow); tc_flow = get_unaligned_be32(&nh->ip6_flow);
flow->tos = (ntohl(tc_flow) >> 4) & IP_DSCP_MASK; flow->tos = ntohl(tc_flow) >> 4;
flow->ipv6_label = tc_flow & htonl(IPV6_LABEL_MASK); flow->ipv6_label = tc_flow & htonl(IPV6_LABEL_MASK);
flow->nw_proto = IPPROTO_NONE; flow->nw_proto = IPPROTO_NONE;
@ -369,7 +369,7 @@ flow_extract(struct ofpbuf *packet, uint32_t priority, ovs_be64 tun_id,
flow->nw_dst = get_unaligned_be32(&nh->ip_dst); flow->nw_dst = get_unaligned_be32(&nh->ip_dst);
flow->nw_proto = nh->ip_proto; flow->nw_proto = nh->ip_proto;
flow->tos = nh->ip_tos & IP_DSCP_MASK; flow->tos = nh->ip_tos;
if (IP_IS_FRAGMENT(nh->ip_frag_off)) { if (IP_IS_FRAGMENT(nh->ip_frag_off)) {
flow->frag = FLOW_FRAG_ANY; flow->frag = FLOW_FRAG_ANY;
if (nh->ip_frag_off & htons(IP_FRAG_OFF_MASK)) { if (nh->ip_frag_off & htons(IP_FRAG_OFF_MASK)) {
@ -525,19 +525,15 @@ flow_format(struct ds *ds, const struct flow *flow)
ntohs(flow->dl_type)); ntohs(flow->dl_type));
if (flow->dl_type == htons(ETH_TYPE_IPV6)) { if (flow->dl_type == htons(ETH_TYPE_IPV6)) {
ds_put_format(ds, " label%#"PRIx32" proto%"PRIu8" tos%"PRIu8" ipv6", ds_put_format(ds, " label%#"PRIx32" proto%"PRIu8" tos%#"PRIx8" ipv6",
ntohl(flow->ipv6_label), flow->nw_proto, ntohl(flow->ipv6_label), flow->nw_proto, flow->tos);
flow->tos & IP_DSCP_MASK);
print_ipv6_addr(ds, &flow->ipv6_src); print_ipv6_addr(ds, &flow->ipv6_src);
ds_put_cstr(ds, "->"); ds_put_cstr(ds, "->");
print_ipv6_addr(ds, &flow->ipv6_dst); print_ipv6_addr(ds, &flow->ipv6_dst);
} else { } else {
ds_put_format(ds, " proto%"PRIu8 ds_put_format(ds, " proto%"PRIu8" tos%#"PRIx8" ip"IP_FMT"->"IP_FMT,
" tos%"PRIu8 flow->nw_proto, flow->tos,
" ip"IP_FMT"->"IP_FMT,
flow->nw_proto,
flow->tos & IP_DSCP_MASK,
IP_ARGS(&flow->nw_src), IP_ARGS(&flow->nw_src),
IP_ARGS(&flow->nw_dst)); IP_ARGS(&flow->nw_dst));
} }
@ -1016,7 +1012,7 @@ flow_compose(struct ofpbuf *b, const struct flow *flow)
b->l3 = ip = ofpbuf_put_zeros(b, sizeof *ip); b->l3 = ip = ofpbuf_put_zeros(b, sizeof *ip);
ip->ip_ihl_ver = IP_IHL_VER(5, 4); ip->ip_ihl_ver = IP_IHL_VER(5, 4);
ip->ip_tos = flow->tos & IP_DSCP_MASK; ip->ip_tos = flow->tos;
ip->ip_proto = flow->nw_proto; ip->ip_proto = flow->nw_proto;
ip->ip_src = flow->nw_src; ip->ip_src = flow->nw_src;
ip->ip_dst = flow->nw_dst; ip->ip_dst = flow->nw_dst;

View File

@ -188,12 +188,19 @@ static const struct mf_field mf_fields[MFF_N_IDS] = {
MFP_IP_ANY, MFP_IP_ANY,
NXM_OF_IP_PROTO, NXM_OF_IP_PROTO,
}, { }, {
MFF_IP_TOS, "nw_tos", NULL, MFF_IP_DSCP, "nw_tos", NULL,
MF_FIELD_SIZES(u8), MF_FIELD_SIZES(u8),
MFM_NONE, 0, MFM_NONE, 0,
MFS_DECIMAL, MFS_DECIMAL,
MFP_IP_ANY, MFP_IP_ANY,
NXM_OF_IP_TOS, NXM_OF_IP_TOS,
}, {
MFF_IP_ECN, "nw_ecn", NULL,
1, 2,
MFM_NONE, 0,
MFS_DECIMAL,
MFP_IP_ANY,
NXM_NX_IP_ECN,
}, { }, {
MFF_IP_FRAG, "ip_frag", NULL, MFF_IP_FRAG, "ip_frag", NULL,
1, 2, 1, 2,
@ -422,8 +429,10 @@ mf_is_all_wild(const struct mf_field *mf, const struct flow_wildcards *wc)
case MFF_IPV6_DST: case MFF_IPV6_DST:
return ipv6_mask_is_any(&wc->ipv6_dst_mask); return ipv6_mask_is_any(&wc->ipv6_dst_mask);
case MFF_IP_TOS: case MFF_IP_DSCP:
return !(wc->tos_mask & IP_DSCP_MASK); return !(wc->tos_mask & IP_DSCP_MASK);
case MFF_IP_ECN:
return !(wc->tos_mask & IP_ECN_MASK);
case MFF_IP_FRAG: case MFF_IP_FRAG:
return !(wc->frag_mask & FLOW_FRAG_MASK); return !(wc->frag_mask & FLOW_FRAG_MASK);
@ -524,9 +533,12 @@ mf_get_mask(const struct mf_field *mf, const struct flow_wildcards *wc,
mask->ipv6 = wc->ipv6_dst_mask; mask->ipv6 = wc->ipv6_dst_mask;
break; break;
case MFF_IP_TOS: case MFF_IP_DSCP:
mask->u8 = wc->tos_mask & IP_DSCP_MASK; mask->u8 = wc->tos_mask & IP_DSCP_MASK;
break; break;
case MFF_IP_ECN:
mask->u8 = wc->tos_mask & IP_ECN_MASK;
break;
case MFF_IP_FRAG: case MFF_IP_FRAG:
mask->u8 = wc->frag_mask & FLOW_FRAG_MASK; mask->u8 = wc->frag_mask & FLOW_FRAG_MASK;
break; break;
@ -643,7 +655,7 @@ mf_are_prereqs_ok(const struct mf_field *mf, const struct flow *flow)
* without the VLAN_CFI bit being set, but we can't reject those values because * without the VLAN_CFI bit being set, but we can't reject those values because
* it is still legitimate to test just for those bits (see the documentation * it is still legitimate to test just for those bits (see the documentation
* for NXM_OF_VLAN_TCI in nicira-ext.h). On the other hand, there is never a * for NXM_OF_VLAN_TCI in nicira-ext.h). On the other hand, there is never a
* reason to set the low bit of MFF_IP_TOS to 1, so we reject that. */ * reason to set the low bit of MFF_IP_DSCP to 1, so we reject that. */
bool bool
mf_is_value_valid(const struct mf_field *mf, const union mf_value *value) mf_is_value_valid(const struct mf_field *mf, const union mf_value *value)
{ {
@ -692,8 +704,10 @@ mf_is_value_valid(const struct mf_field *mf, const union mf_value *value)
case MFF_ND_TLL: case MFF_ND_TLL:
return true; return true;
case MFF_IP_TOS: case MFF_IP_DSCP:
return !(value->u8 & ~IP_DSCP_MASK); return !(value->u8 & ~IP_DSCP_MASK);
case MFF_IP_ECN:
return !(value->u8 & ~IP_ECN_MASK);
case MFF_IP_FRAG: case MFF_IP_FRAG:
return !(value->u8 & ~FLOW_FRAG_MASK); return !(value->u8 & ~FLOW_FRAG_MASK);
@ -799,10 +813,14 @@ mf_get_value(const struct mf_field *mf, const struct flow *flow,
value->u8 = flow->nw_proto; value->u8 = flow->nw_proto;
break; break;
case MFF_IP_TOS: case MFF_IP_DSCP:
value->u8 = flow->tos & IP_DSCP_MASK; value->u8 = flow->tos & IP_DSCP_MASK;
break; break;
case MFF_IP_ECN:
value->u8 = flow->tos & IP_ECN_MASK;
break;
case MFF_IP_FRAG: case MFF_IP_FRAG:
value->u8 = flow->frag; value->u8 = flow->frag;
break; break;
@ -950,8 +968,12 @@ mf_set_value(const struct mf_field *mf,
cls_rule_set_nw_proto(rule, value->u8); cls_rule_set_nw_proto(rule, value->u8);
break; break;
case MFF_IP_TOS: case MFF_IP_DSCP:
cls_rule_set_nw_tos(rule, value->u8); cls_rule_set_nw_dscp(rule, value->u8);
break;
case MFF_IP_ECN:
cls_rule_set_nw_ecn(rule, value->u8);
break; break;
case MFF_IP_FRAG: case MFF_IP_FRAG:
@ -1117,11 +1139,16 @@ mf_set_wild(const struct mf_field *mf, struct cls_rule *rule)
rule->flow.nw_proto = 0; rule->flow.nw_proto = 0;
break; break;
case MFF_IP_TOS: case MFF_IP_DSCP:
rule->wc.tos_mask |= IP_DSCP_MASK; rule->wc.tos_mask |= IP_DSCP_MASK;
rule->flow.tos &= ~IP_DSCP_MASK; rule->flow.tos &= ~IP_DSCP_MASK;
break; break;
case MFF_IP_ECN:
rule->wc.tos_mask |= IP_ECN_MASK;
rule->flow.tos &= ~IP_ECN_MASK;
break;
case MFF_IP_FRAG: case MFF_IP_FRAG:
rule->wc.frag_mask |= FLOW_FRAG_MASK; rule->wc.frag_mask |= FLOW_FRAG_MASK;
rule->flow.frag &= ~FLOW_FRAG_MASK; rule->flow.frag &= ~FLOW_FRAG_MASK;
@ -1201,7 +1228,8 @@ mf_set(const struct mf_field *mf,
case MFF_VLAN_PCP: case MFF_VLAN_PCP:
case MFF_IPV6_LABEL: case MFF_IPV6_LABEL:
case MFF_IP_PROTO: case MFF_IP_PROTO:
case MFF_IP_TOS: case MFF_IP_DSCP:
case MFF_IP_ECN:
case MFF_ARP_OP: case MFF_ARP_OP:
case MFF_ARP_SHA: case MFF_ARP_SHA:
case MFF_ARP_THA: case MFF_ARP_THA:
@ -1424,8 +1452,12 @@ mf_random_value(const struct mf_field *mf, union mf_value *value)
value->be32 &= ~htonl(IPV6_LABEL_MASK); value->be32 &= ~htonl(IPV6_LABEL_MASK);
break; break;
case MFF_IP_TOS: case MFF_IP_DSCP:
value->u8 &= ~0x03; value->u8 &= IP_DSCP_MASK;
break;
case MFF_IP_ECN:
value->u8 &= IP_ECN_MASK;
break; break;
case MFF_IP_FRAG: case MFF_IP_FRAG:

View File

@ -70,7 +70,8 @@ enum mf_field_id {
MFF_IPV6_LABEL, /* be32 */ MFF_IPV6_LABEL, /* be32 */
MFF_IP_PROTO, /* u8 (used for IPv4 or IPv6) */ MFF_IP_PROTO, /* u8 (used for IPv4 or IPv6) */
MFF_IP_TOS, /* u8 (used for IPv4 or IPv6) */ MFF_IP_DSCP, /* u8 (used for IPv4 or IPv6) */
MFF_IP_ECN, /* u8 (used for IPv4 or IPv6) */
MFF_IP_FRAG, /* u8 (used for IPv4 or IPv6) */ MFF_IP_FRAG, /* u8 (used for IPv4 or IPv6) */
MFF_ARP_OP, /* be16 */ MFF_ARP_OP, /* be16 */

View File

@ -492,6 +492,10 @@ nx_put_match(struct ofpbuf *b, const struct cls_rule *cr)
nxm_put_8(b, NXM_OF_IP_TOS, flow->tos & IP_DSCP_MASK); nxm_put_8(b, NXM_OF_IP_TOS, flow->tos & IP_DSCP_MASK);
} }
if (cr->wc.tos_mask & IP_ECN_MASK) {
nxm_put_8(b, NXM_NX_IP_ECN, flow->tos & IP_ECN_MASK);
}
if (!(wc & FWW_NW_PROTO)) { if (!(wc & FWW_NW_PROTO)) {
nxm_put_8(b, NXM_OF_IP_PROTO, flow->nw_proto); nxm_put_8(b, NXM_OF_IP_PROTO, flow->nw_proto);
switch (flow->nw_proto) { switch (flow->nw_proto) {
@ -542,6 +546,10 @@ nx_put_match(struct ofpbuf *b, const struct cls_rule *cr)
nxm_put_8(b, NXM_OF_IP_TOS, flow->tos & IP_DSCP_MASK); nxm_put_8(b, NXM_OF_IP_TOS, flow->tos & IP_DSCP_MASK);
} }
if (cr->wc.tos_mask & IP_ECN_MASK) {
nxm_put_8(b, NXM_NX_IP_ECN, flow->tos & IP_ECN_MASK);
}
if (!(wc & FWW_NW_PROTO)) { if (!(wc & FWW_NW_PROTO)) {
nxm_put_8(b, NXM_OF_IP_PROTO, flow->nw_proto); nxm_put_8(b, NXM_OF_IP_PROTO, flow->nw_proto);
switch (flow->nw_proto) { switch (flow->nw_proto) {
@ -1047,6 +1055,9 @@ nxm_read_field(const struct nxm_field *src, const struct flow *flow)
case NFI_NXM_OF_IP_TOS: case NFI_NXM_OF_IP_TOS:
return flow->tos & IP_DSCP_MASK; return flow->tos & IP_DSCP_MASK;
case NFI_NXM_NX_IP_ECN:
return flow->tos & IP_ECN_MASK;
case NFI_NXM_NX_IP_FRAG: case NFI_NXM_NX_IP_FRAG:
return flow->frag; return flow->frag;
@ -1202,6 +1213,11 @@ nxm_write_field(const struct nxm_field *dst, struct flow *flow,
flow->tos |= new_value & IP_DSCP_MASK; flow->tos |= new_value & IP_DSCP_MASK;
break; break;
case NFI_NXM_NX_IP_ECN:
flow->tos &= ~IP_ECN_MASK;
flow->tos |= new_value & IP_ECN_MASK;
break;
case NFI_NXM_NX_IP_FRAG: case NFI_NXM_NX_IP_FRAG:
flow->frag = new_value; flow->frag = new_value;
break; break;

View File

@ -26,7 +26,7 @@ DEFINE_FIELD_M(OF_ETH_DST, MFF_ETH_DST, true)
DEFINE_FIELD (OF_ETH_SRC, MFF_ETH_SRC, true) DEFINE_FIELD (OF_ETH_SRC, MFF_ETH_SRC, true)
DEFINE_FIELD (OF_ETH_TYPE, MFF_ETH_TYPE, false) DEFINE_FIELD (OF_ETH_TYPE, MFF_ETH_TYPE, false)
DEFINE_FIELD_M(OF_VLAN_TCI, MFF_VLAN_TCI, true) DEFINE_FIELD_M(OF_VLAN_TCI, MFF_VLAN_TCI, true)
DEFINE_FIELD (OF_IP_TOS, MFF_IP_TOS, true) DEFINE_FIELD (OF_IP_TOS, MFF_IP_DSCP, true)
DEFINE_FIELD (OF_IP_PROTO, MFF_IP_PROTO, false) DEFINE_FIELD (OF_IP_PROTO, MFF_IP_PROTO, false)
DEFINE_FIELD_M(OF_IP_SRC, MFF_IPV4_SRC, true) DEFINE_FIELD_M(OF_IP_SRC, MFF_IPV4_SRC, true)
DEFINE_FIELD_M(OF_IP_DST, MFF_IPV4_DST, true) DEFINE_FIELD_M(OF_IP_DST, MFF_IPV4_DST, true)
@ -45,6 +45,7 @@ DEFINE_FIELD (NX_ARP_THA, MFF_ARP_THA, false)
DEFINE_FIELD_M(NX_IPV6_SRC, MFF_IPV6_SRC, false) DEFINE_FIELD_M(NX_IPV6_SRC, MFF_IPV6_SRC, false)
DEFINE_FIELD_M(NX_IPV6_DST, MFF_IPV6_DST, false) DEFINE_FIELD_M(NX_IPV6_DST, MFF_IPV6_DST, false)
DEFINE_FIELD (NX_IPV6_LABEL, MFF_IPV6_LABEL,false) DEFINE_FIELD (NX_IPV6_LABEL, MFF_IPV6_LABEL,false)
DEFINE_FIELD (NX_IP_ECN, MFF_IP_ECN, true)
/* XXX should we have MFF_ICMPV4_TYPE and MFF_ICMPV6_TYPE? */ /* XXX should we have MFF_ICMPV4_TYPE and MFF_ICMPV6_TYPE? */
DEFINE_FIELD (NX_ICMPV6_TYPE,MFF_ICMP_TYPE, false) DEFINE_FIELD (NX_ICMPV6_TYPE,MFF_ICMP_TYPE, false)
DEFINE_FIELD (NX_ICMPV6_CODE,MFF_ICMP_CODE, false) DEFINE_FIELD (NX_ICMPV6_CODE,MFF_ICMP_CODE, false)

View File

@ -102,6 +102,7 @@ nxm_decode_n_bits(ovs_be16 ofs_nbits)
* NXM_OF_ETH_TYPE 4 2 -- 6 * NXM_OF_ETH_TYPE 4 2 -- 6
* NXM_OF_VLAN_TCI 4 2 2 8 * NXM_OF_VLAN_TCI 4 2 2 8
* NXM_OF_IP_TOS 4 1 -- 5 * NXM_OF_IP_TOS 4 1 -- 5
* NXM_NX_IP_ECN 4 1 -- 5
* NXM_NX_IP_FRAG 4 1 1 8 * NXM_NX_IP_FRAG 4 1 1 8
* NXM_OF_IP_PROTO 4 2 -- 6 * NXM_OF_IP_PROTO 4 2 -- 6
* NXM_OF_IPV6_SRC_W 4 16 16 36 * NXM_OF_IPV6_SRC_W 4 16 16 36
@ -118,7 +119,7 @@ nxm_decode_n_bits(ovs_be16 ofs_nbits)
* NXM_NX_REG_W(4) 4 4 4 12 * NXM_NX_REG_W(4) 4 4 4 12
* NXM_NX_TUN_ID_W 4 8 8 20 * NXM_NX_TUN_ID_W 4 8 8 20
* ------------------------------------------- * -------------------------------------------
* total 265 * total 270
* *
* So this value is conservative. * So this value is conservative.
*/ */

View File

@ -370,7 +370,7 @@ format_odp_key_attr(const struct nlattr *a, struct ds *ds)
case OVS_KEY_ATTR_IPV4: case OVS_KEY_ATTR_IPV4:
ipv4_key = nl_attr_get(a); ipv4_key = nl_attr_get(a);
ds_put_format(ds, "ipv4(src="IP_FMT",dst="IP_FMT"," ds_put_format(ds, "ipv4(src="IP_FMT",dst="IP_FMT","
"proto=%"PRId8",tos=%"PRIu8",frag=%s)", "proto=%"PRId8",tos=%#"PRIx8",frag=%s)",
IP_ARGS(&ipv4_key->ipv4_src), IP_ARGS(&ipv4_key->ipv4_src),
IP_ARGS(&ipv4_key->ipv4_dst), IP_ARGS(&ipv4_key->ipv4_dst),
ipv4_key->ipv4_proto, ipv4_key->ipv4_tos, ipv4_key->ipv4_proto, ipv4_key->ipv4_tos,
@ -386,7 +386,7 @@ format_odp_key_attr(const struct nlattr *a, struct ds *ds)
inet_ntop(AF_INET6, ipv6_key->ipv6_dst, dst_str, sizeof dst_str); inet_ntop(AF_INET6, ipv6_key->ipv6_dst, dst_str, sizeof dst_str);
ds_put_format(ds, "ipv6(src=%s,dst=%s,label=%#"PRIx32",proto=%"PRId8 ds_put_format(ds, "ipv6(src=%s,dst=%s,label=%#"PRIx32",proto=%"PRId8
",tos=%"PRIu8",frag=%s)", ",tos=%#"PRIx8",frag=%s)",
src_str, dst_str, ntohl(ipv6_key->ipv6_label), src_str, dst_str, ntohl(ipv6_key->ipv6_label),
ipv6_key->ipv6_proto, ipv6_key->ipv6_tos, ipv6_key->ipv6_proto, ipv6_key->ipv6_tos,
ovs_frag_type_to_string(ipv6_key->ipv6_frag)); ovs_frag_type_to_string(ipv6_key->ipv6_frag));
@ -876,7 +876,7 @@ odp_flow_key_from_flow(struct ofpbuf *buf, const struct flow *flow)
ipv4_key->ipv4_src = flow->nw_src; ipv4_key->ipv4_src = flow->nw_src;
ipv4_key->ipv4_dst = flow->nw_dst; ipv4_key->ipv4_dst = flow->nw_dst;
ipv4_key->ipv4_proto = flow->nw_proto; ipv4_key->ipv4_proto = flow->nw_proto;
ipv4_key->ipv4_tos = flow->tos & IP_DSCP_MASK; ipv4_key->ipv4_tos = flow->tos;
ipv4_key->ipv4_frag = ovs_to_odp_frag(flow->frag); ipv4_key->ipv4_frag = ovs_to_odp_frag(flow->frag);
} else if (flow->dl_type == htons(ETH_TYPE_IPV6)) { } else if (flow->dl_type == htons(ETH_TYPE_IPV6)) {
struct ovs_key_ipv6 *ipv6_key; struct ovs_key_ipv6 *ipv6_key;
@ -888,7 +888,7 @@ odp_flow_key_from_flow(struct ofpbuf *buf, const struct flow *flow)
memcpy(ipv6_key->ipv6_dst, &flow->ipv6_dst, sizeof ipv6_key->ipv6_dst); memcpy(ipv6_key->ipv6_dst, &flow->ipv6_dst, sizeof ipv6_key->ipv6_dst);
ipv6_key->ipv6_label = flow->ipv6_label; ipv6_key->ipv6_label = flow->ipv6_label;
ipv6_key->ipv6_proto = flow->nw_proto; ipv6_key->ipv6_proto = flow->nw_proto;
ipv6_key->ipv6_tos = flow->tos & IP_DSCP_MASK; ipv6_key->ipv6_tos = flow->tos;
ipv6_key->ipv6_frag = ovs_to_odp_frag(flow->frag); ipv6_key->ipv6_frag = ovs_to_odp_frag(flow->frag);
} else if (flow->dl_type == htons(ETH_TYPE_ARP)) { } else if (flow->dl_type == htons(ETH_TYPE_ARP)) {
struct ovs_key_arp *arp_key; struct ovs_key_arp *arp_key;

View File

@ -897,6 +897,11 @@ ofputil_min_flow_format(const struct cls_rule *rule)
return NXFF_NXM; return NXFF_NXM;
} }
/* Only NXM supports matching IP ECN bits. */
if (wc->tos_mask & IP_ECN_MASK) {
return NXFF_NXM;
}
/* Other formats can express this rule. */ /* Other formats can express this rule. */
return NXFF_OPENFLOW10; return NXFF_OPENFLOW10;
} }

View File

@ -3680,7 +3680,7 @@ commit_set_nw_action(const struct flow *flow, struct flow *base,
ipv4_key.ipv4_src = base->nw_src = flow->nw_src; ipv4_key.ipv4_src = base->nw_src = flow->nw_src;
ipv4_key.ipv4_dst = base->nw_dst = flow->nw_dst; ipv4_key.ipv4_dst = base->nw_dst = flow->nw_dst;
ipv4_key.ipv4_proto = base->nw_proto; ipv4_key.ipv4_proto = base->nw_proto;
ipv4_key.ipv4_tos = flow->tos & IP_DSCP_MASK; ipv4_key.ipv4_tos = flow->tos;
ipv4_key.ipv4_frag = (base->frag == 0 ? OVS_FRAG_TYPE_NONE ipv4_key.ipv4_frag = (base->frag == 0 ? OVS_FRAG_TYPE_NONE
: base->frag == FLOW_FRAG_ANY ? OVS_FRAG_TYPE_FIRST : base->frag == FLOW_FRAG_ANY ? OVS_FRAG_TYPE_FIRST
: OVS_FRAG_TYPE_LATER); : OVS_FRAG_TYPE_LATER);

View File

@ -4,15 +4,17 @@ AT_SETUP([OVS datapath parsing and formatting - valid forms])
AT_DATA([odp-base.txt], [dnl AT_DATA([odp-base.txt], [dnl
in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15) in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15)
in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x1234) in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x1234)
in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x0800),ipv4(src=35.8.2.41,dst=172.16.0.20,proto=5,tos=128,frag=no) in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x0800),ipv4(src=35.8.2.41,dst=172.16.0.20,proto=5,tos=0x80,frag=no)
in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x0800),ipv4(src=35.8.2.41,dst=172.16.0.20,proto=5,tos=128,frag=first) in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x0800),ipv4(src=35.8.2.41,dst=172.16.0.20,proto=5,tos=0x81,frag=no)
in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x0800),ipv4(src=35.8.2.41,dst=172.16.0.20,proto=5,tos=128,frag=later) in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x0800),ipv4(src=35.8.2.41,dst=172.16.0.20,proto=5,tos=0x80,frag=first)
in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x0800),ipv4(src=35.8.2.41,dst=172.16.0.20,proto=5,tos=0x80,frag=later)
in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x0800),ipv4(src=35.8.2.41,dst=172.16.0.20,proto=6,tos=0,frag=no),tcp(src=80,dst=8080) in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x0800),ipv4(src=35.8.2.41,dst=172.16.0.20,proto=6,tos=0,frag=no),tcp(src=80,dst=8080)
in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x0800),ipv4(src=35.8.2.41,dst=172.16.0.20,proto=17,tos=0,frag=no),udp(src=81,dst=6632) in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x0800),ipv4(src=35.8.2.41,dst=172.16.0.20,proto=17,tos=0,frag=no),udp(src=81,dst=6632)
in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x0800),ipv4(src=35.8.2.41,dst=172.16.0.20,proto=1,tos=0,frag=no),icmp(type=1,code=2) in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x0800),ipv4(src=35.8.2.41,dst=172.16.0.20,proto=1,tos=0,frag=no),icmp(type=1,code=2)
in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x86dd),ipv6(src=::1,dst=::2,label=0,proto=10,tos=112,frag=no) in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x86dd),ipv6(src=::1,dst=::2,label=0,proto=10,tos=0x70,frag=no)
in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x86dd),ipv6(src=::1,dst=::2,label=0,proto=10,tos=112,frag=first) in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x86dd),ipv6(src=::1,dst=::2,label=0,proto=10,tos=0x71,frag=no)
in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x86dd),ipv6(src=::1,dst=::2,label=0,proto=10,tos=112,frag=later) in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x86dd),ipv6(src=::1,dst=::2,label=0,proto=10,tos=0x70,frag=first)
in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x86dd),ipv6(src=::1,dst=::2,label=0,proto=10,tos=0x70,frag=later)
in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x86dd),ipv6(src=::1,dst=::2,label=0,proto=6,tos=0,frag=no),tcp(src=80,dst=8080) in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x86dd),ipv6(src=::1,dst=::2,label=0,proto=6,tos=0,frag=no),tcp(src=80,dst=8080)
in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x86dd),ipv6(src=::1,dst=::2,label=0,proto=17,tos=0,frag=no),udp(src=6630,dst=22) in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x86dd),ipv6(src=::1,dst=::2,label=0,proto=17,tos=0,frag=no),udp(src=6630,dst=22)
in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x86dd),ipv6(src=::1,dst=::2,label=0,proto=58,tos=0,frag=no),icmpv6(type=1,code=2) in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x86dd),ipv6(src=::1,dst=::2,label=0,proto=58,tos=0,frag=no),icmpv6(type=1,code=2)

View File

@ -211,8 +211,14 @@ NXM_OF_VLAN_TCI_W(0000/e000) # No 802.1Q or with VID=0
# IP TOS # IP TOS
NXM_OF_ETH_TYPE(0800) NXM_OF_IP_TOS(f0) NXM_OF_ETH_TYPE(0800) NXM_OF_IP_TOS(f0)
NXM_OF_ETH_TYPE(0800) NXM_OF_IP_TOS(41)
NXM_OF_IP_TOS(f0) NXM_OF_IP_TOS(f0)
# IP ECN
NXM_OF_ETH_TYPE(0800) NXM_NX_IP_ECN(03)
NXM_OF_ETH_TYPE(0800) NXM_NX_IP_ECN(06)
NXM_NX_IP_ECN(03)
# IP protocol # IP protocol
NXM_OF_ETH_TYPE(0800) NXM_OF_IP_PROTO(01) NXM_OF_ETH_TYPE(0800) NXM_OF_IP_PROTO(01)
NXM_OF_ETH_TYPE(0800) NXM_OF_IP_PROTO(05) NXM_OF_ETH_TYPE(0800) NXM_OF_IP_PROTO(05)
@ -389,6 +395,12 @@ NXM_OF_VLAN_TCI_W(0000/e000)
# IP TOS # IP TOS
NXM_OF_ETH_TYPE(0800), NXM_OF_IP_TOS(f0) NXM_OF_ETH_TYPE(0800), NXM_OF_IP_TOS(f0)
nx_pull_match() returned error 44010102 (type OFPET_BAD_REQUEST, code NXBRC_NXM_BAD_VALUE)
nx_pull_match() returned error 44010104 (type OFPET_BAD_REQUEST, code NXBRC_NXM_BAD_PREREQ)
# IP ECN
NXM_OF_ETH_TYPE(0800), NXM_NX_IP_ECN(03)
nx_pull_match() returned error 44010102 (type OFPET_BAD_REQUEST, code NXBRC_NXM_BAD_VALUE)
nx_pull_match() returned error 44010104 (type OFPET_BAD_REQUEST, code NXBRC_NXM_BAD_PREREQ) nx_pull_match() returned error 44010104 (type OFPET_BAD_REQUEST, code NXBRC_NXM_BAD_PREREQ)
# IP protocol # IP protocol

View File

@ -408,6 +408,14 @@ When \fBdl_type\fR is wildcarded or set to a value other than 0x0800 or
0x86dd, the value of \fBnw_tos\fR is ignored (see \fBFlow Syntax\fR 0x86dd, the value of \fBnw_tos\fR is ignored (see \fBFlow Syntax\fR
above). above).
. .
.IP \fBnw_ecn=\fIecn\fR
Matches \fIecn\fR bits in IP ToS or IPv6 traffic class fields, which is
specified as a decimal number between 0 and 3, inclusive.
.IP
When \fBdl_type\fR is wildcarded or set to a value other than 0x0800 or
0x86dd, the value of \fBnw_ecn\fR is ignored (see \fBFlow Syntax\fR
above).
.
.IP \fBtp_src=\fIport\fR .IP \fBtp_src=\fIport\fR
.IQ \fBtp_dst=\fIport\fR .IQ \fBtp_dst=\fIport\fR
When \fBdl_type\fR and \fBnw_proto\fR specify TCP or UDP, \fBtp_src\fR When \fBdl_type\fR and \fBnw_proto\fR specify TCP or UDP, \fBtp_src\fR