Add support for hardware filters to cxgb(4). The T3 chip can inspect
L2/3/4 headers and can drop or steer packets as instructed. Filtering based on src ip, dst ip, src port, dst port, 802.1q, udp/tcp, and mac addr is possible. Add support in cxgbtool to program these filters. Some simple examples: Drop all tcp/80 traffic coming from the subnet specified. # cxgbtool cxgb2 filter 0 sip 192.168.1.0/24 dport 80 type tcp action drop Steer all incoming UDP traffic to qset 0. # cxgbtool cxgb2 filter 1 type udp queue 0 action pass Steer all tcp traffic from 192.168.1.1 to qset 1. # cxgbtool cxgb2 filter 2 sip 192.168.1.1 type tcp queue 1 action pass Drop fragments. # cxgbtool cxgb2 filter 3 type frag action drop List all filters. # cxgbtool cxgb2 filter list index SIP DIP sport dport VLAN PRI P/MAC type Q 0 192.168.1.0/24 0.0.0.0 * 80 0 0/1 */* tcp - 1 0.0.0.0/0 0.0.0.0 * * 0 0/1 */* udp 0 2 192.168.1.1/32 0.0.0.0 * * 0 0/1 */* tcp 1 3 0.0.0.0/0 0.0.0.0 * * 0 0/1 */* frag - 16367 0.0.0.0/0 0.0.0.0 * * 0 0/1 */* * * MFC after: 2 weeks
This commit is contained in:
parent
4045471dea
commit
30b63b91fa
@ -59,6 +59,9 @@ enum {
|
||||
CH_CLEAR_STATS,
|
||||
CH_GET_UP_LA,
|
||||
CH_GET_UP_IOQS,
|
||||
CH_SET_FILTER,
|
||||
CH_DEL_FILTER,
|
||||
CH_GET_FILTER,
|
||||
};
|
||||
|
||||
/* statistics categories */
|
||||
@ -215,6 +218,29 @@ struct ch_up_ioqs {
|
||||
struct t3_ioq_entry *data;
|
||||
};
|
||||
|
||||
struct ch_filter_tuple {
|
||||
uint32_t sip;
|
||||
uint32_t dip;
|
||||
uint16_t sport;
|
||||
uint16_t dport;
|
||||
uint16_t vlan:12;
|
||||
uint16_t vlan_prio:3;
|
||||
};
|
||||
|
||||
struct ch_filter {
|
||||
uint32_t filter_id;
|
||||
struct ch_filter_tuple val;
|
||||
struct ch_filter_tuple mask;
|
||||
uint16_t mac_addr_idx;
|
||||
uint8_t mac_hit:1;
|
||||
uint8_t proto:2;
|
||||
|
||||
uint8_t want_filter_id:1;
|
||||
uint8_t pass:1;
|
||||
uint8_t rss:1;
|
||||
uint8_t qset;
|
||||
};
|
||||
|
||||
#define CHELSIO_SETREG _IOW('f', CH_SETREG, struct ch_reg)
|
||||
#define CHELSIO_GETREG _IOWR('f', CH_GETREG, struct ch_reg)
|
||||
#define CHELSIO_GETMTUTAB _IOR('f', CH_GETMTUTAB, struct ch_mtus)
|
||||
@ -239,4 +265,7 @@ struct ch_up_ioqs {
|
||||
#define CHELSIO_GET_EEPROM _IOWR('f', CH_GET_EEPROM, struct ch_eeprom)
|
||||
#define CHELSIO_GET_UP_LA _IOWR('f', CH_GET_UP_LA, struct ch_up_la)
|
||||
#define CHELSIO_GET_UP_IOQS _IOWR('f', CH_GET_UP_IOQS, struct ch_up_ioqs)
|
||||
#define CHELSIO_SET_FILTER _IOW('f', CH_SET_FILTER, struct ch_filter)
|
||||
#define CHELSIO_DEL_FILTER _IOW('f', CH_DEL_FILTER, struct ch_filter)
|
||||
#define CHELSIO_GET_FILTER _IOWR('f', CH_GET_FILTER, struct ch_filter)
|
||||
#endif
|
||||
|
@ -99,6 +99,13 @@ static void cxgb_ext_intr_handler(void *, int);
|
||||
static void cxgb_tick_handler(void *, int);
|
||||
static void cxgb_tick(void *);
|
||||
static void setup_rss(adapter_t *sc);
|
||||
static int alloc_filters(struct adapter *);
|
||||
static int setup_hw_filters(struct adapter *);
|
||||
static int set_filter(struct adapter *, int, const struct filter_info *);
|
||||
static inline void mk_set_tcb_field(struct cpl_set_tcb_field *, unsigned int,
|
||||
unsigned int, u64, u64);
|
||||
static inline void set_tcb_field_ulp(struct cpl_set_tcb_field *, unsigned int,
|
||||
unsigned int, u64, u64);
|
||||
|
||||
/* Attachment glue for the PCI controller end of the device. Each port of
|
||||
* the device is attached separately, as defined later.
|
||||
@ -1661,6 +1668,13 @@ cxgb_up(struct adapter *sc)
|
||||
if ((err = update_tpsram(sc)))
|
||||
goto out;
|
||||
|
||||
if (is_offload(sc)) {
|
||||
sc->params.mc5.nservers = 0;
|
||||
sc->params.mc5.nroutes = 0;
|
||||
sc->params.mc5.nfilters = t3_mc5_size(&sc->mc5) -
|
||||
MC5_MIN_TIDS;
|
||||
}
|
||||
|
||||
err = t3_init_hw(sc, 0);
|
||||
if (err)
|
||||
goto out;
|
||||
@ -1672,6 +1686,7 @@ cxgb_up(struct adapter *sc)
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
alloc_filters(sc);
|
||||
setup_rss(sc);
|
||||
|
||||
t3_intr_clear(sc);
|
||||
@ -1698,6 +1713,7 @@ cxgb_up(struct adapter *sc)
|
||||
|
||||
if (!(sc->flags & QUEUES_BOUND)) {
|
||||
bind_qsets(sc);
|
||||
setup_hw_filters(sc);
|
||||
sc->flags |= QUEUES_BOUND;
|
||||
}
|
||||
|
||||
@ -3076,6 +3092,139 @@ cxgb_extension_ioctl(struct cdev *dev, unsigned long cmd, caddr_t data,
|
||||
free(buf, M_DEVBUF);
|
||||
break;
|
||||
}
|
||||
case CHELSIO_SET_FILTER: {
|
||||
struct ch_filter *f = (struct ch_filter *)data;;
|
||||
struct filter_info *p;
|
||||
unsigned int nfilters = sc->params.mc5.nfilters;
|
||||
|
||||
if (!is_offload(sc))
|
||||
return (EOPNOTSUPP); /* No TCAM */
|
||||
if (!(sc->flags & FULL_INIT_DONE))
|
||||
return (EAGAIN); /* mc5 not setup yet */
|
||||
if (nfilters == 0)
|
||||
return (EBUSY); /* TOE will use TCAM */
|
||||
|
||||
/* sanity checks */
|
||||
if (f->filter_id >= nfilters ||
|
||||
(f->val.dip && f->mask.dip != 0xffffffff) ||
|
||||
(f->val.sport && f->mask.sport != 0xffff) ||
|
||||
(f->val.dport && f->mask.dport != 0xffff) ||
|
||||
(f->val.vlan && f->mask.vlan != 0xfff) ||
|
||||
(f->val.vlan_prio &&
|
||||
f->mask.vlan_prio != FILTER_NO_VLAN_PRI) ||
|
||||
(f->mac_addr_idx != 0xffff && f->mac_addr_idx > 15) ||
|
||||
f->qset >= SGE_QSETS ||
|
||||
sc->rrss_map[f->qset] >= RSS_TABLE_SIZE)
|
||||
return (EINVAL);
|
||||
|
||||
/* Was allocated with M_WAITOK */
|
||||
KASSERT(sc->filters, ("filter table NULL\n"));
|
||||
|
||||
p = &sc->filters[f->filter_id];
|
||||
if (p->locked)
|
||||
return (EPERM);
|
||||
|
||||
bzero(p, sizeof(*p));
|
||||
p->sip = f->val.sip;
|
||||
p->sip_mask = f->mask.sip;
|
||||
p->dip = f->val.dip;
|
||||
p->sport = f->val.sport;
|
||||
p->dport = f->val.dport;
|
||||
p->vlan = f->mask.vlan ? f->val.vlan : 0xfff;
|
||||
p->vlan_prio = f->mask.vlan_prio ? (f->val.vlan_prio & 6) :
|
||||
FILTER_NO_VLAN_PRI;
|
||||
p->mac_hit = f->mac_hit;
|
||||
p->mac_vld = f->mac_addr_idx != 0xffff;
|
||||
p->mac_idx = f->mac_addr_idx;
|
||||
p->pkt_type = f->proto;
|
||||
p->report_filter_id = f->want_filter_id;
|
||||
p->pass = f->pass;
|
||||
p->rss = f->rss;
|
||||
p->qset = f->qset;
|
||||
|
||||
error = set_filter(sc, f->filter_id, p);
|
||||
if (error == 0)
|
||||
p->valid = 1;
|
||||
break;
|
||||
}
|
||||
case CHELSIO_DEL_FILTER: {
|
||||
struct ch_filter *f = (struct ch_filter *)data;
|
||||
struct filter_info *p;
|
||||
unsigned int nfilters = sc->params.mc5.nfilters;
|
||||
|
||||
if (!is_offload(sc))
|
||||
return (EOPNOTSUPP);
|
||||
if (!(sc->flags & FULL_INIT_DONE))
|
||||
return (EAGAIN);
|
||||
if (nfilters == 0 || sc->filters == NULL)
|
||||
return (EINVAL);
|
||||
if (f->filter_id >= nfilters)
|
||||
return (EINVAL);
|
||||
|
||||
p = &sc->filters[f->filter_id];
|
||||
if (p->locked)
|
||||
return (EPERM);
|
||||
if (!p->valid)
|
||||
return (EFAULT); /* Read "Bad address" as "Bad index" */
|
||||
|
||||
bzero(p, sizeof(*p));
|
||||
p->sip = p->sip_mask = 0xffffffff;
|
||||
p->vlan = 0xfff;
|
||||
p->vlan_prio = FILTER_NO_VLAN_PRI;
|
||||
p->pkt_type = 1;
|
||||
error = set_filter(sc, f->filter_id, p);
|
||||
break;
|
||||
}
|
||||
case CHELSIO_GET_FILTER: {
|
||||
struct ch_filter *f = (struct ch_filter *)data;
|
||||
struct filter_info *p;
|
||||
unsigned int i, nfilters = sc->params.mc5.nfilters;
|
||||
|
||||
if (!is_offload(sc))
|
||||
return (EOPNOTSUPP);
|
||||
if (!(sc->flags & FULL_INIT_DONE))
|
||||
return (EAGAIN);
|
||||
if (nfilters == 0 || sc->filters == NULL)
|
||||
return (EINVAL);
|
||||
|
||||
i = f->filter_id == 0xffffffff ? 0 : f->filter_id + 1;
|
||||
for (; i < nfilters; i++) {
|
||||
p = &sc->filters[i];
|
||||
if (!p->valid)
|
||||
continue;
|
||||
|
||||
bzero(f, sizeof(*f));
|
||||
|
||||
f->filter_id = i;
|
||||
f->val.sip = p->sip;
|
||||
f->mask.sip = p->sip_mask;
|
||||
f->val.dip = p->dip;
|
||||
f->mask.dip = p->dip ? 0xffffffff : 0;
|
||||
f->val.sport = p->sport;
|
||||
f->mask.sport = p->sport ? 0xffff : 0;
|
||||
f->val.dport = p->dport;
|
||||
f->mask.dport = p->dport ? 0xffff : 0;
|
||||
f->val.vlan = p->vlan == 0xfff ? 0 : p->vlan;
|
||||
f->mask.vlan = p->vlan == 0xfff ? 0 : 0xfff;
|
||||
f->val.vlan_prio = p->vlan_prio == FILTER_NO_VLAN_PRI ?
|
||||
0 : p->vlan_prio;
|
||||
f->mask.vlan_prio = p->vlan_prio == FILTER_NO_VLAN_PRI ?
|
||||
0 : FILTER_NO_VLAN_PRI;
|
||||
f->mac_hit = p->mac_hit;
|
||||
f->mac_addr_idx = p->mac_vld ? p->mac_idx : 0xffff;
|
||||
f->proto = p->pkt_type;
|
||||
f->want_filter_id = p->report_filter_id;
|
||||
f->pass = p->pass;
|
||||
f->rss = p->rss;
|
||||
f->qset = p->qset;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (i == nfilters)
|
||||
f->filter_id = 0xffffffff;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return (EOPNOTSUPP);
|
||||
break;
|
||||
@ -3130,5 +3279,129 @@ cxgb_get_regs(adapter_t *sc, struct ch_ifconf_regs *regs, uint8_t *buf)
|
||||
XGM_REG(A_XGM_RX_SPI4_SOP_EOP_CNT, 1));
|
||||
}
|
||||
|
||||
static int
|
||||
alloc_filters(struct adapter *sc)
|
||||
{
|
||||
struct filter_info *p;
|
||||
unsigned int nfilters = sc->params.mc5.nfilters;
|
||||
|
||||
if (nfilters == 0)
|
||||
return (0);
|
||||
|
||||
p = malloc(sizeof(*p) * nfilters, M_DEVBUF, M_WAITOK | M_ZERO);
|
||||
sc->filters = p;
|
||||
|
||||
p = &sc->filters[nfilters - 1];
|
||||
p->vlan = 0xfff;
|
||||
p->vlan_prio = FILTER_NO_VLAN_PRI;
|
||||
p->pass = p->rss = p->valid = p->locked = 1;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
setup_hw_filters(struct adapter *sc)
|
||||
{
|
||||
int i, rc;
|
||||
unsigned int nfilters = sc->params.mc5.nfilters;
|
||||
|
||||
if (!sc->filters)
|
||||
return (0);
|
||||
|
||||
t3_enable_filters(sc);
|
||||
|
||||
for (i = rc = 0; i < nfilters && !rc; i++) {
|
||||
if (sc->filters[i].locked)
|
||||
rc = set_filter(sc, i, &sc->filters[i]);
|
||||
}
|
||||
|
||||
return (rc);
|
||||
}
|
||||
|
||||
static int
|
||||
set_filter(struct adapter *sc, int id, const struct filter_info *f)
|
||||
{
|
||||
int len;
|
||||
struct mbuf *m;
|
||||
struct ulp_txpkt *txpkt;
|
||||
struct work_request_hdr *wr;
|
||||
struct cpl_pass_open_req *oreq;
|
||||
struct cpl_set_tcb_field *sreq;
|
||||
|
||||
len = sizeof(*wr) + sizeof(*oreq) + 2 * sizeof(*sreq);
|
||||
KASSERT(len <= MHLEN, ("filter request too big for an mbuf"));
|
||||
|
||||
id += t3_mc5_size(&sc->mc5) - sc->params.mc5.nroutes -
|
||||
sc->params.mc5.nfilters;
|
||||
|
||||
m = m_gethdr(M_WAITOK, MT_DATA);
|
||||
m->m_len = m->m_pkthdr.len = len;
|
||||
bzero(mtod(m, char *), len);
|
||||
|
||||
wr = mtod(m, struct work_request_hdr *);
|
||||
wr->wrh_hi = htonl(V_WR_OP(FW_WROPCODE_BYPASS) | F_WR_ATOMIC);
|
||||
|
||||
oreq = (struct cpl_pass_open_req *)(wr + 1);
|
||||
txpkt = (struct ulp_txpkt *)oreq;
|
||||
txpkt->cmd_dest = htonl(V_ULPTX_CMD(ULP_TXPKT));
|
||||
txpkt->len = htonl(V_ULPTX_NFLITS(sizeof(*oreq) / 8));
|
||||
OPCODE_TID(oreq) = htonl(MK_OPCODE_TID(CPL_PASS_OPEN_REQ, id));
|
||||
oreq->local_port = htons(f->dport);
|
||||
oreq->peer_port = htons(f->sport);
|
||||
oreq->local_ip = htonl(f->dip);
|
||||
oreq->peer_ip = htonl(f->sip);
|
||||
oreq->peer_netmask = htonl(f->sip_mask);
|
||||
oreq->opt0h = 0;
|
||||
oreq->opt0l = htonl(F_NO_OFFLOAD);
|
||||
oreq->opt1 = htonl(V_MAC_MATCH_VALID(f->mac_vld) |
|
||||
V_CONN_POLICY(CPL_CONN_POLICY_FILTER) |
|
||||
V_VLAN_PRI(f->vlan_prio >> 1) |
|
||||
V_VLAN_PRI_VALID(f->vlan_prio != FILTER_NO_VLAN_PRI) |
|
||||
V_PKT_TYPE(f->pkt_type) | V_OPT1_VLAN(f->vlan) |
|
||||
V_MAC_MATCH(f->mac_idx | (f->mac_hit << 4)));
|
||||
|
||||
sreq = (struct cpl_set_tcb_field *)(oreq + 1);
|
||||
set_tcb_field_ulp(sreq, id, 1, 0x1800808000ULL,
|
||||
(f->report_filter_id << 15) | (1 << 23) |
|
||||
((u64)f->pass << 35) | ((u64)!f->rss << 36));
|
||||
set_tcb_field_ulp(sreq + 1, id, 0, 0xffffffff, (2 << 19) | 1);
|
||||
t3_mgmt_tx(sc, m);
|
||||
|
||||
if (f->pass && !f->rss) {
|
||||
len = sizeof(*sreq);
|
||||
m = m_gethdr(M_WAITOK, MT_DATA);
|
||||
m->m_len = m->m_pkthdr.len = len;
|
||||
bzero(mtod(m, char *), len);
|
||||
sreq = mtod(m, struct cpl_set_tcb_field *);
|
||||
sreq->wr.wrh_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));
|
||||
mk_set_tcb_field(sreq, id, 25, 0x3f80000,
|
||||
(u64)sc->rrss_map[f->qset] << 19);
|
||||
t3_mgmt_tx(sc, m);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void
|
||||
mk_set_tcb_field(struct cpl_set_tcb_field *req, unsigned int tid,
|
||||
unsigned int word, u64 mask, u64 val)
|
||||
{
|
||||
OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_SET_TCB_FIELD, tid));
|
||||
req->reply = V_NO_REPLY(1);
|
||||
req->cpu_idx = 0;
|
||||
req->word = htons(word);
|
||||
req->mask = htobe64(mask);
|
||||
req->val = htobe64(val);
|
||||
}
|
||||
|
||||
static inline void
|
||||
set_tcb_field_ulp(struct cpl_set_tcb_field *req, unsigned int tid,
|
||||
unsigned int word, u64 mask, u64 val)
|
||||
{
|
||||
struct ulp_txpkt *txpkt = (struct ulp_txpkt *)req;
|
||||
|
||||
txpkt->cmd_dest = htonl(V_ULPTX_CMD(ULP_TXPKT));
|
||||
txpkt->len = htonl(V_ULPTX_NFLITS(sizeof(*req) / 8));
|
||||
mk_set_tcb_field(req, tid, word, mask, val);
|
||||
}
|
||||
|
||||
MODULE_DEPEND(if_cxgb, cxgb_t3fw, 1, 1, 1);
|
||||
|
@ -1,6 +1,6 @@
|
||||
/**************************************************************************
|
||||
|
||||
Copyright (c) 2007-2009, Chelsio Inc.
|
||||
Copyright (c) 2007-2010, Chelsio Inc.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
@ -93,6 +93,9 @@ usage(FILE *fp)
|
||||
"\tclearstats clear MAC statistics\n"
|
||||
"\tcontext <type> <id> show an SGE context\n"
|
||||
"\tdesc <qset> <queue> <idx> [<cnt>] dump SGE descriptors\n"
|
||||
"\tfilter <idx> [<param> <val>] ... set a filter\n"
|
||||
"\tfilter <idx> delete|clear delete a filter\n"
|
||||
"\tfilter list list all filters\n"
|
||||
"\tioqs dump uP IOQs\n"
|
||||
"\tla dump uP logic analyzer info\n"
|
||||
"\tloadboot <boot image> download boot image\n"
|
||||
@ -1177,24 +1180,25 @@ parse_ipaddr(const char *s, uint32_t *addr, uint32_t *mask)
|
||||
* Parse a string containing a value and an optional colon separated mask.
|
||||
*/
|
||||
static int
|
||||
parse_val_mask_param(const char *s, uint32_t *val, uint32_t *mask)
|
||||
parse_val_mask_param(const char *s, uint32_t *val, uint32_t *mask,
|
||||
uint32_t default_mask)
|
||||
{
|
||||
char *p;
|
||||
|
||||
*mask = 0xffffffffU;
|
||||
*mask = default_mask;
|
||||
*val = strtoul(s, &p, 0);
|
||||
if (p == s)
|
||||
if (p == s || *val > default_mask)
|
||||
return -1;
|
||||
if (*p == ':' && p[1])
|
||||
*mask = strtoul(p + 1, &p, 0);
|
||||
return *p ? -1 : 0;
|
||||
return *p || *mask > default_mask ? -1 : 0;
|
||||
}
|
||||
|
||||
static int
|
||||
parse_trace_param(const char *s, uint32_t *val, uint32_t *mask)
|
||||
{
|
||||
return strchr(s, '.') ? parse_ipaddr(s, val, mask) :
|
||||
parse_val_mask_param(s, val, mask);
|
||||
parse_val_mask_param(s, val, mask, 0xffffffffU);
|
||||
}
|
||||
|
||||
static int
|
||||
@ -1273,6 +1277,174 @@ trace_config(int argc, char *argv[], int start_arg, const char *iff_name)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
show_filters(const char *iff_name)
|
||||
{
|
||||
static const char *pkt_type[] = { "*", "tcp", "udp", "frag" };
|
||||
struct ch_filter op;
|
||||
union {
|
||||
uint32_t nip;
|
||||
uint8_t octet[4];
|
||||
} nsip, ndip;
|
||||
char sip[20], dip[20];
|
||||
int header = 0;
|
||||
|
||||
bzero(&op, sizeof(op));
|
||||
op.filter_id = 0xffffffff;
|
||||
|
||||
do {
|
||||
if (doit(iff_name, CHELSIO_GET_FILTER, &op) < 0)
|
||||
err(1, "list filters");
|
||||
|
||||
if (op.filter_id == 0xffffffff)
|
||||
break;
|
||||
|
||||
if (!header) {
|
||||
printf("index SIP DIP sport "
|
||||
"dport VLAN PRI P/MAC type Q\n");
|
||||
header = 1;
|
||||
}
|
||||
|
||||
nsip.nip = htonl(op.val.sip);
|
||||
ndip.nip = htonl(op.val.dip);
|
||||
|
||||
sprintf(sip, "%u.%u.%u.%u/%-2u", nsip.octet[0], nsip.octet[1],
|
||||
nsip.octet[2], nsip.octet[3],
|
||||
op.mask.sip ? 33 - ffs(op.mask.sip) : 0);
|
||||
sprintf(dip, "%u.%u.%u.%u", ndip.octet[0], ndip.octet[1],
|
||||
ndip.octet[2], ndip.octet[3]);
|
||||
printf("%5zu %18s %15s ", (size_t)op.filter_id, sip, dip);
|
||||
printf(op.val.sport ? "%5u " : " * ", op.val.sport);
|
||||
printf(op.val.dport ? "%5u " : " * ", op.val.dport);
|
||||
printf(op.val.vlan != 0xfff ? "%4u " : " * ", op.val.vlan);
|
||||
printf(op.val.vlan_prio == 7 ? " * " :
|
||||
"%1u/%1u ", op.val.vlan_prio, op.val.vlan_prio | 1);
|
||||
if (op.mac_addr_idx == 0xffff)
|
||||
printf("*/* ");
|
||||
else if (op.mac_hit)
|
||||
printf("%1u/%3u ", (op.mac_addr_idx >> 3) & 0x1,
|
||||
(op.mac_addr_idx) & 0x7);
|
||||
else
|
||||
printf("%1u/ * ", (op.mac_addr_idx >> 3) & 0x1);
|
||||
printf("%4s ", pkt_type[op.proto]);
|
||||
if (!op.pass)
|
||||
printf("-\n");
|
||||
else if (op.rss)
|
||||
printf("*\n");
|
||||
else
|
||||
printf("%1u\n", op.qset);
|
||||
} while (1);
|
||||
}
|
||||
|
||||
static int
|
||||
filter_config(int argc, char *argv[], int start_arg, const char *iff_name)
|
||||
{
|
||||
int ret = 0;
|
||||
uint32_t val, mask;
|
||||
struct ch_filter op;
|
||||
|
||||
if (argc < start_arg + 1)
|
||||
return -1;
|
||||
|
||||
memset(&op, 0, sizeof(op));
|
||||
op.mac_addr_idx = 0xffff;
|
||||
op.rss = 1;
|
||||
|
||||
if (argc == start_arg + 1 && !strcmp(argv[start_arg], "list")) {
|
||||
show_filters(iff_name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (get_int_arg(argv[start_arg++], &op.filter_id))
|
||||
return -1;
|
||||
if (argc == start_arg + 1 && (!strcmp(argv[start_arg], "delete") ||
|
||||
!strcmp(argv[start_arg], "clear"))) {
|
||||
if (doit(iff_name, CHELSIO_DEL_FILTER, &op) < 0) {
|
||||
if (errno == EBUSY)
|
||||
err(1, "no filter support when offload in use");
|
||||
err(1, "delete filter");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
while (start_arg + 2 <= argc) {
|
||||
if (!strcmp(argv[start_arg], "sip")) {
|
||||
ret = parse_ipaddr(argv[start_arg + 1], &op.val.sip,
|
||||
&op.mask.sip);
|
||||
} else if (!strcmp(argv[start_arg], "dip")) {
|
||||
ret = parse_ipaddr(argv[start_arg + 1], &op.val.dip,
|
||||
&op.mask.dip);
|
||||
} else if (!strcmp(argv[start_arg], "sport")) {
|
||||
ret = parse_val_mask_param(argv[start_arg + 1],
|
||||
&val, &mask, 0xffff);
|
||||
op.val.sport = val;
|
||||
op.mask.sport = mask;
|
||||
} else if (!strcmp(argv[start_arg], "dport")) {
|
||||
ret = parse_val_mask_param(argv[start_arg + 1],
|
||||
&val, &mask, 0xffff);
|
||||
op.val.dport = val;
|
||||
op.mask.dport = mask;
|
||||
} else if (!strcmp(argv[start_arg], "vlan")) {
|
||||
ret = parse_val_mask_param(argv[start_arg + 1],
|
||||
&val, &mask, 0xfff);
|
||||
op.val.vlan = val;
|
||||
op.mask.vlan = mask;
|
||||
} else if (!strcmp(argv[start_arg], "prio")) {
|
||||
ret = parse_val_mask_param(argv[start_arg + 1],
|
||||
&val, &mask, 7);
|
||||
op.val.vlan_prio = val;
|
||||
op.mask.vlan_prio = mask;
|
||||
} else if (!strcmp(argv[start_arg], "mac")) {
|
||||
if (!strcmp(argv[start_arg + 1], "none"))
|
||||
val = -1;
|
||||
else
|
||||
ret = get_int_arg(argv[start_arg + 1], &val);
|
||||
op.mac_hit = val != (uint32_t)-1;
|
||||
op.mac_addr_idx = op.mac_hit ? val : 0;
|
||||
} else if (!strcmp(argv[start_arg], "type")) {
|
||||
if (!strcmp(argv[start_arg + 1], "tcp"))
|
||||
op.proto = 1;
|
||||
else if (!strcmp(argv[start_arg + 1], "udp"))
|
||||
op.proto = 2;
|
||||
else if (!strcmp(argv[start_arg + 1], "frag"))
|
||||
op.proto = 3;
|
||||
else
|
||||
errx(1, "unknown type \"%s\"; must be one of "
|
||||
"\"tcp\", \"udp\", or \"frag\"",
|
||||
argv[start_arg + 1]);
|
||||
} else if (!strcmp(argv[start_arg], "queue")) {
|
||||
ret = get_int_arg(argv[start_arg + 1], &val);
|
||||
op.qset = val;
|
||||
op.rss = 0;
|
||||
} else if (!strcmp(argv[start_arg], "action")) {
|
||||
if (!strcmp(argv[start_arg + 1], "pass"))
|
||||
op.pass = 1;
|
||||
else if (strcmp(argv[start_arg + 1], "drop"))
|
||||
errx(1, "unknown action \"%s\"; must be one of "
|
||||
"\"pass\" or \"drop\"",
|
||||
argv[start_arg + 1]);
|
||||
} else
|
||||
errx(1, "unknown filter parameter \"%s\"\n"
|
||||
"known parameters are \"mac\", \"sip\", "
|
||||
"\"dip\", \"sport\", \"dport\", \"vlan\", "
|
||||
"\"prio\", \"type\", \"queue\", and \"action\"",
|
||||
argv[start_arg]);
|
||||
if (ret < 0)
|
||||
errx(1, "bad value \"%s\" for parameter \"%s\"",
|
||||
argv[start_arg + 1], argv[start_arg]);
|
||||
start_arg += 2;
|
||||
}
|
||||
if (start_arg != argc)
|
||||
errx(1, "no value for \"%s\"", argv[start_arg]);
|
||||
|
||||
if (doit(iff_name, CHELSIO_SET_FILTER, &op) < 0) {
|
||||
if (errno == EBUSY)
|
||||
err(1, "no filter support when offload in use");
|
||||
err(1, "set filter");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
static int
|
||||
get_sched_param(int argc, char *argv[], int pos, unsigned int *valp)
|
||||
{
|
||||
@ -1501,6 +1673,8 @@ run_cmd(int argc, char *argv[], const char *iff_name)
|
||||
r = pktsched(argc, argv, 3, iff_name);
|
||||
else if (!strcmp(argv[2], "tcb"))
|
||||
r = get_tcb2(argc, argv, 3, iff_name);
|
||||
else if (!strcmp(argv[2], "filter"))
|
||||
r = filter_config(argc, argv, 3, iff_name);
|
||||
else if (!strcmp(argv[2], "clearstats"))
|
||||
r = clear_stats(argc, argv, 3, iff_name);
|
||||
else if (!strcmp(argv[2], "la"))
|
||||
|
Loading…
Reference in New Issue
Block a user