blob: c300ec619c8ac7183592d5340c3eb32a9057f5fd [file] [log] [blame]
/*
*
* Copyright (C) 2014 Mindspeed Technologies, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "cmm.h"
#include "fpp_private.h"
#include "fpp.h"
#include "cmmd.h"
#include "itf.h"
#include "module_lro.h"
struct lro_interface {
char ifname[IFNAMSIZ];
int used;
};
#define LRO_MAX_ITF 4
static struct lro_interface lro_itf[LRO_MAX_ITF];
int lro_interface_add(char *ifname)
{
int i;
for (i = 0; i < LRO_MAX_ITF; i++)
{
if (lro_itf[i].used)
continue;
cmm_print(DEBUG_INFO, "%s: lro interface added\n", ifname);
strncpy(lro_itf[i].ifname, ifname, IFNAMSIZ);
lro_itf[i].used = 1;
return 0;
}
return -1;
}
void lro_interface_update(struct interface *itf)
{
int i;
char cmd[32 + IFNAMSIZ];
for (i = 0; i < LRO_MAX_ITF; i++)
{
if (lro_itf[i].used && !strcmp(lro_itf[i].ifname, itf->ifname)) {
cmm_print(DEBUG_INFO, "%s: lro enabled\n", itf->ifname);
itf->flags |= ITF_LRO;
snprintf(cmd, 32 + IFNAMSIZ, "ethtool -K %s lro on", itf->ifname);
system(cmd);
break;
}
}
}
void lro_socket_open(FCI_CLIENT *fci_handle, struct ctTable *ctEntry)
{
unsigned char proto;
struct socket *s;
const unsigned int *daddr, *saddr;
unsigned short dport, sport;
struct nf_conntrack *ct = ctEntry->ct;
int ifindex;
struct interface *itf;
if (ctEntry->family != AF_INET)
return;
proto = nfct_get_attr_u8(ct, ATTR_ORIG_L4PROTO);
if (proto != IPPROTO_TCP)
return;
if (ctEntry->flags & LOCAL_CONN_ORIG) {
ifindex = nfct_get_attr_u32(ct, ATTR_REPL_COMCERTO_FP_IFINDEX);
saddr = nfct_get_attr(ct, ATTR_REPL_IPV4_SRC);
daddr = nfct_get_attr(ct, ATTR_ORIG_IPV4_SRC);
sport = nfct_get_attr_u16(ct, ATTR_REPL_PORT_SRC);
dport = nfct_get_attr_u16(ct, ATTR_ORIG_PORT_SRC);
} else {
ifindex = nfct_get_attr_u32(ct, ATTR_ORIG_COMCERTO_FP_IFINDEX);
saddr = nfct_get_attr(ct, ATTR_ORIG_IPV4_SRC);
daddr = nfct_get_attr(ct, ATTR_REPL_IPV4_SRC);
sport = nfct_get_attr_u16(ct, ATTR_ORIG_PORT_SRC);
dport = nfct_get_attr_u16(ct, ATTR_REPL_PORT_SRC);
}
itf = __itf_find(ifindex);
if (!itf)
return;
if (!(itf->flags & ITF_LRO))
return;
if (!____itf_is_programmed(itf))
return;
__pthread_mutex_lock(&socket_lock);
s = socket_find_by_addr(AF_INET, saddr, daddr, sport, dport, IPPROTO_TCP);
if (!s) {
s = malloc(sizeof(struct socket));
if (!s) {
cmm_print(DEBUG_ERROR, "%s: malloc() failed\n", __func__);
goto unlock;
}
memset(s, 0, sizeof(struct socket));
s->family = AF_INET;
s->id = new_socket_id();
if (!s->id) {
cmm_print(DEBUG_ERROR, "%s: No Socket ID available \n", __func__);
free(s);
goto unlock;
}
s->type = CMMD_SOCKET_TYPE_LRO;
s->mode = SOCKET_CONNECTED;
memcpy(s->saddr, saddr, IPADDRLEN(s->family));
memcpy(s->daddr, daddr, IPADDRLEN(s->family));
s->sport = sport;
s->dport = dport;
s->proto = IPPROTO_TCP;
s->dscp = 0;
s->fwmark = 0;
s->queue = 0;
__socket_add(s);
}
__socket_open(fci_handle, s);
unlock:
__pthread_mutex_unlock(&socket_lock);
}
void lro_socket_close(FCI_CLIENT *fci_handle, FCI_CLIENT *fci_key_handle, struct ctTable *ctEntry)
{
unsigned char proto;
struct socket *s;
const unsigned int *daddr, *saddr;
unsigned short dport, sport;
struct nf_conntrack *ct = ctEntry->ct;
if (ctEntry->family != AF_INET)
return;
proto = nfct_get_attr_u8(ct, ATTR_ORIG_L4PROTO);
if (proto != IPPROTO_TCP)
return;
if (ctEntry->flags & LOCAL_CONN_ORIG) {
saddr = nfct_get_attr(ct, ATTR_REPL_IPV4_SRC);
daddr = nfct_get_attr(ct, ATTR_ORIG_IPV4_SRC);
sport = nfct_get_attr_u16(ct, ATTR_REPL_PORT_SRC);
dport = nfct_get_attr_u16(ct, ATTR_ORIG_PORT_SRC);
} else {
saddr = nfct_get_attr(ct, ATTR_ORIG_IPV4_SRC);
daddr = nfct_get_attr(ct, ATTR_REPL_IPV4_SRC);
sport = nfct_get_attr_u16(ct, ATTR_ORIG_PORT_SRC);
dport = nfct_get_attr_u16(ct, ATTR_REPL_PORT_SRC);
}
__pthread_mutex_lock(&socket_lock);
s = socket_find_by_addr(AF_INET, saddr, daddr, sport, dport, IPPROTO_TCP);
if (!s)
goto unlock;
__socket_close(fci_handle, fci_key_handle, s);
unlock:
__pthread_mutex_unlock(&socket_lock);
}