2009-07-08 13:19:16 -07:00
|
|
|
|
/*
|
2010-04-13 16:50:31 -07:00
|
|
|
|
* Copyright (c) 2009, 2010 Nicira Networks.
|
2009-07-08 13:19:16 -07:00
|
|
|
|
*
|
2009-06-15 15:11:30 -07:00
|
|
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
|
* you may not use this file except in compliance with the License.
|
|
|
|
|
* You may obtain a copy of the License at:
|
2009-07-08 13:19:16 -07:00
|
|
|
|
*
|
2009-06-15 15:11:30 -07:00
|
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
|
*
|
|
|
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
|
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
|
* See the License for the specific language governing permissions and
|
|
|
|
|
* limitations under the License.
|
2009-07-08 13:19:16 -07:00
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include <config.h>
|
|
|
|
|
#include "odp-util.h"
|
|
|
|
|
#include <inttypes.h>
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
#include "coverage.h"
|
|
|
|
|
#include "dynamic-string.h"
|
|
|
|
|
#include "flow.h"
|
|
|
|
|
#include "packets.h"
|
|
|
|
|
#include "timeval.h"
|
|
|
|
|
#include "util.h"
|
|
|
|
|
|
|
|
|
|
union odp_action *
|
|
|
|
|
odp_actions_add(struct odp_actions *actions, uint16_t type)
|
|
|
|
|
{
|
|
|
|
|
union odp_action *a;
|
2010-08-04 10:50:40 -07:00
|
|
|
|
size_t idx;
|
|
|
|
|
|
|
|
|
|
idx = actions->n_actions++ & (MAX_ODP_ACTIONS - 1);
|
|
|
|
|
a = &actions->actions[idx];
|
2009-07-08 13:19:16 -07:00
|
|
|
|
memset(a, 0, sizeof *a);
|
|
|
|
|
a->type = type;
|
|
|
|
|
return a;
|
|
|
|
|
}
|
|
|
|
|
|
2010-10-11 13:31:35 -07:00
|
|
|
|
void
|
|
|
|
|
format_odp_flow_key(struct ds *ds, const struct odp_flow_key *key)
|
|
|
|
|
{
|
2010-10-08 16:26:21 -07:00
|
|
|
|
ds_put_format(ds, "in_port%04x tci(", key->in_port);
|
|
|
|
|
if (key->dl_tci) {
|
|
|
|
|
ds_put_format(ds, "vlan%"PRIu16",pcp%d",
|
|
|
|
|
vlan_tci_to_vid(key->dl_tci),
|
|
|
|
|
vlan_tci_to_pcp(key->dl_tci));
|
|
|
|
|
} else {
|
|
|
|
|
ds_put_char(ds, '0');
|
|
|
|
|
}
|
|
|
|
|
ds_put_format(ds, ") mac"ETH_ADDR_FMT"->"ETH_ADDR_FMT" type%04x "
|
|
|
|
|
"proto%"PRId8" tos%"PRIu8" ip"IP_FMT"->"IP_FMT" port%d->%d",
|
2010-10-11 13:31:35 -07:00
|
|
|
|
ETH_ADDR_ARGS(key->dl_src), ETH_ADDR_ARGS(key->dl_dst),
|
|
|
|
|
ntohs(key->dl_type), key->nw_proto, key->nw_tos,
|
|
|
|
|
IP_ARGS(&key->nw_src), IP_ARGS(&key->nw_dst),
|
|
|
|
|
ntohs(key->tp_src), ntohs(key->tp_dst));
|
|
|
|
|
}
|
|
|
|
|
|
2009-07-08 13:19:16 -07:00
|
|
|
|
void
|
|
|
|
|
format_odp_action(struct ds *ds, const union odp_action *a)
|
|
|
|
|
{
|
|
|
|
|
switch (a->type) {
|
|
|
|
|
case ODPAT_OUTPUT:
|
|
|
|
|
ds_put_format(ds, "%"PRIu16, a->output.port);
|
|
|
|
|
break;
|
|
|
|
|
case ODPAT_CONTROLLER:
|
|
|
|
|
ds_put_format(ds, "ctl(%"PRIu32")", a->controller.arg);
|
|
|
|
|
break;
|
2010-04-12 11:49:16 -04:00
|
|
|
|
case ODPAT_SET_TUNNEL:
|
|
|
|
|
ds_put_format(ds, "set_tunnel(0x%08"PRIx32")", ntohl(a->tunnel.tun_id));
|
|
|
|
|
break;
|
2010-10-08 16:26:21 -07:00
|
|
|
|
case ODPAT_SET_DL_TCI: {
|
|
|
|
|
int vid = vlan_tci_to_vid(a->dl_tci.tci);
|
|
|
|
|
int pcp = vlan_tci_to_pcp(a->dl_tci.tci);
|
|
|
|
|
|
|
|
|
|
switch (ntohs(a->dl_tci.mask)) {
|
|
|
|
|
case VLAN_VID_MASK:
|
|
|
|
|
ds_put_format(ds, "set_tci(vlan=%d)", vid);
|
|
|
|
|
break;
|
|
|
|
|
case VLAN_PCP_MASK:
|
|
|
|
|
ds_put_format(ds, "set_tci(pcp=%d)", pcp);
|
|
|
|
|
break;
|
|
|
|
|
case VLAN_VID_MASK | VLAN_PCP_MASK:
|
|
|
|
|
ds_put_format(ds, "set_tci(vlan=%d,pcp=%d)", vid, pcp);
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
ds_put_format(ds, "set_tci(tci=%04"PRIx16",mask=%04"PRIx16")",
|
|
|
|
|
ntohs(a->dl_tci.tci), ntohs(a->dl_tci.mask));
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
2009-07-08 13:19:16 -07:00
|
|
|
|
break;
|
|
|
|
|
case ODPAT_STRIP_VLAN:
|
|
|
|
|
ds_put_format(ds, "strip_vlan");
|
|
|
|
|
break;
|
|
|
|
|
case ODPAT_SET_DL_SRC:
|
|
|
|
|
ds_put_format(ds, "set_dl_src("ETH_ADDR_FMT")",
|
|
|
|
|
ETH_ADDR_ARGS(a->dl_addr.dl_addr));
|
|
|
|
|
break;
|
|
|
|
|
case ODPAT_SET_DL_DST:
|
|
|
|
|
ds_put_format(ds, "set_dl_dst("ETH_ADDR_FMT")",
|
|
|
|
|
ETH_ADDR_ARGS(a->dl_addr.dl_addr));
|
|
|
|
|
break;
|
|
|
|
|
case ODPAT_SET_NW_SRC:
|
|
|
|
|
ds_put_format(ds, "set_nw_src("IP_FMT")",
|
|
|
|
|
IP_ARGS(&a->nw_addr.nw_addr));
|
|
|
|
|
break;
|
|
|
|
|
case ODPAT_SET_NW_DST:
|
|
|
|
|
ds_put_format(ds, "set_nw_dst("IP_FMT")",
|
|
|
|
|
IP_ARGS(&a->nw_addr.nw_addr));
|
|
|
|
|
break;
|
2009-11-11 14:59:49 -08:00
|
|
|
|
case ODPAT_SET_NW_TOS:
|
|
|
|
|
ds_put_format(ds, "set_nw_tos(%"PRIu8")", a->nw_tos.nw_tos);
|
|
|
|
|
break;
|
2009-07-08 13:19:16 -07:00
|
|
|
|
case ODPAT_SET_TP_SRC:
|
|
|
|
|
ds_put_format(ds, "set_tp_src(%"PRIu16")", ntohs(a->tp_port.tp_port));
|
|
|
|
|
break;
|
|
|
|
|
case ODPAT_SET_TP_DST:
|
|
|
|
|
ds_put_format(ds, "set_tp_dst(%"PRIu16")", ntohs(a->tp_port.tp_port));
|
|
|
|
|
break;
|
2010-07-16 15:30:09 -07:00
|
|
|
|
case ODPAT_SET_PRIORITY:
|
|
|
|
|
ds_put_format(ds, "set_priority(0x%"PRIx32")", a->priority.priority);
|
|
|
|
|
break;
|
|
|
|
|
case ODPAT_POP_PRIORITY:
|
|
|
|
|
ds_put_cstr(ds, "pop_priority");
|
|
|
|
|
break;
|
2010-09-15 13:26:08 -07:00
|
|
|
|
case ODPAT_DROP_SPOOFED_ARP:
|
|
|
|
|
ds_put_cstr(ds, "drop_spoofed_arp");
|
|
|
|
|
break;
|
2009-07-08 13:19:16 -07:00
|
|
|
|
default:
|
2010-04-13 16:50:31 -07:00
|
|
|
|
ds_put_format(ds, "***bad action 0x%"PRIx16"***", a->type);
|
2009-07-08 13:19:16 -07:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
format_odp_actions(struct ds *ds, const union odp_action *actions,
|
|
|
|
|
size_t n_actions)
|
|
|
|
|
{
|
|
|
|
|
size_t i;
|
|
|
|
|
for (i = 0; i < n_actions; i++) {
|
|
|
|
|
if (i) {
|
|
|
|
|
ds_put_char(ds, ',');
|
|
|
|
|
}
|
|
|
|
|
format_odp_action(ds, &actions[i]);
|
|
|
|
|
}
|
|
|
|
|
if (!n_actions) {
|
|
|
|
|
ds_put_cstr(ds, "drop");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
format_odp_flow_stats(struct ds *ds, const struct odp_flow_stats *s)
|
|
|
|
|
{
|
2009-11-06 10:43:50 -08:00
|
|
|
|
ds_put_format(ds, "packets:%llu, bytes:%llu, used:",
|
|
|
|
|
(unsigned long long int) s->n_packets,
|
|
|
|
|
(unsigned long long int) s->n_bytes);
|
2009-07-08 13:19:16 -07:00
|
|
|
|
if (s->used_sec) {
|
|
|
|
|
long long int used = s->used_sec * 1000 + s->used_nsec / 1000000;
|
|
|
|
|
ds_put_format(ds, "%.3fs", (time_msec() - used) / 1000.0);
|
|
|
|
|
} else {
|
|
|
|
|
ds_put_format(ds, "never");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
format_odp_flow(struct ds *ds, const struct odp_flow *f)
|
|
|
|
|
{
|
2010-10-11 13:31:35 -07:00
|
|
|
|
format_odp_flow_key(ds, &f->key);
|
2009-07-08 13:19:16 -07:00
|
|
|
|
ds_put_cstr(ds, ", ");
|
|
|
|
|
format_odp_flow_stats(ds, &f->stats);
|
|
|
|
|
ds_put_cstr(ds, ", actions:");
|
|
|
|
|
format_odp_actions(ds, f->actions, f->n_actions);
|
|
|
|
|
}
|
2010-10-11 13:31:35 -07:00
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
odp_flow_key_from_flow(struct odp_flow_key *key, const struct flow *flow)
|
|
|
|
|
{
|
|
|
|
|
key->tun_id = flow->tun_id;
|
|
|
|
|
key->nw_src = flow->nw_src;
|
|
|
|
|
key->nw_dst = flow->nw_dst;
|
|
|
|
|
key->in_port = flow->in_port;
|
2010-10-08 16:26:21 -07:00
|
|
|
|
if (flow->dl_vlan == htons(OFP_VLAN_NONE)) {
|
|
|
|
|
key->dl_tci = htons(0);
|
|
|
|
|
} else {
|
|
|
|
|
uint16_t vid = flow->dl_vlan & htons(VLAN_VID_MASK);
|
|
|
|
|
uint16_t pcp = htons((flow->dl_vlan_pcp << VLAN_PCP_SHIFT)
|
|
|
|
|
& VLAN_PCP_MASK);
|
|
|
|
|
key->dl_tci = vid | pcp | htons(ODP_TCI_PRESENT);
|
|
|
|
|
}
|
2010-10-11 13:31:35 -07:00
|
|
|
|
key->dl_type = flow->dl_type;
|
|
|
|
|
key->tp_src = flow->tp_src;
|
|
|
|
|
key->tp_dst = flow->tp_dst;
|
|
|
|
|
memcpy(key->dl_src, flow->dl_src, ETH_ADDR_LEN);
|
|
|
|
|
memcpy(key->dl_dst, flow->dl_dst, ETH_ADDR_LEN);
|
|
|
|
|
key->nw_proto = flow->nw_proto;
|
|
|
|
|
key->nw_tos = flow->nw_tos;
|
|
|
|
|
}
|
2009-07-08 13:19:16 -07:00
|
|
|
|
|
2010-10-11 13:31:35 -07:00
|
|
|
|
void
|
|
|
|
|
odp_flow_key_to_flow(const struct odp_flow_key *key, struct flow *flow)
|
|
|
|
|
{
|
|
|
|
|
flow->tun_id = key->tun_id;
|
|
|
|
|
flow->nw_src = key->nw_src;
|
|
|
|
|
flow->nw_dst = key->nw_dst;
|
|
|
|
|
flow->in_port = key->in_port;
|
2010-10-08 16:26:21 -07:00
|
|
|
|
if (key->dl_tci) {
|
|
|
|
|
flow->dl_vlan = htons(vlan_tci_to_vid(key->dl_tci));
|
|
|
|
|
flow->dl_vlan_pcp = vlan_tci_to_pcp(key->dl_tci);
|
|
|
|
|
} else {
|
|
|
|
|
flow->dl_vlan = htons(OFP_VLAN_NONE);
|
|
|
|
|
flow->dl_vlan_pcp = 0;
|
|
|
|
|
}
|
2010-10-11 13:31:35 -07:00
|
|
|
|
flow->dl_type = key->dl_type;
|
|
|
|
|
flow->tp_src = key->tp_src;
|
|
|
|
|
flow->tp_dst = key->tp_dst;
|
|
|
|
|
memcpy(flow->dl_src, key->dl_src, ETH_ADDR_LEN);
|
|
|
|
|
memcpy(flow->dl_dst, key->dl_dst, ETH_ADDR_LEN);
|
|
|
|
|
flow->nw_proto = key->nw_proto;
|
|
|
|
|
flow->nw_tos = key->nw_tos;
|
|
|
|
|
}
|