blob: 9af8fde5cdba6742c522b47f5c492750d4c7a447 [file] [log] [blame]
/*
*
* Copyright (C) 2007 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 <signal.h>
#include <libnetfilter_conntrack/libnetfilter_conntrack.h>
#include <libnetfilter_conntrack/libnetfilter_conntrack_tcp.h>
#include <net/if.h>
#include "cmm.h"
#include "itf.h"
#include "ffbridge.h"
#include "fpp.h"
#include "cmmd.h"
#include "fpp_private.h"
#define CTCMD_FLAGS_ORIG_DISABLED (1 << 0)
#define CTCMD_FLAGS_REP_DISABLED (1 << 1)
#define CTCMD_FLAGS_PERMANENT (1 << 2)
/* CtExCommand FORMAT bitfield DEFINES*/
#define CT_SECURE (1 << 0)
#define CT_ORIG_TUNNEL_SIT (1 << 1)
#define CT_REPL_TUNNEL_SIT (1 << 2)
#define CT_ORIG_TUNNEL_4o6 CT_ORIG_TUNNEL_SIT
#define CT_REPL_TUNNEL_4o6 CT_REPL_TUNNEL_SIT
/*****************************************************************
* cmmFeReset
*
*
******************************************************************/
void cmmFeReset(FCI_CLIENT *fci_handle)
{
int i;
struct ctTable *ctEntry;
struct FlowEntry *FlowEntry;
struct RtEntry *rtEntry;
struct NeighborEntry *neigh;
struct socket *socket;
struct list_head *entry;
cmm_print(DEBUG_ERROR, "%s: start\n", __func__);
__pthread_mutex_lock(&itf_table.lock);
__pthread_mutex_lock(&ctMutex);
__pthread_mutex_lock(&rtMutex);
__pthread_mutex_lock(&neighMutex);
__pthread_mutex_lock(&flowMutex);
__pthread_mutex_lock(&socket_lock);
__pthread_mutex_lock(&brMutex);
// Send message to forward engine
cmm_print(DEBUG_COMMAND, "Send CMD_IPV4_RESET\n");
if (fci_write(fci_handle, FPP_CMD_IPV4_RESET, 0, NULL))
{
cmm_print(DEBUG_ERROR, "Error while trying to reset IPv4 forward Engine\n");
goto unlock;
}
cmm_print(DEBUG_COMMAND, "Send CMD_IPV6_RESET\n");
if (fci_write(fci_handle, FPP_CMD_IPV6_RESET, 0, NULL))
{
cmm_print(DEBUG_ERROR, "Error while trying to reset IPv6 forward Engine\n");
goto unlock;
}
for (i = 0; i < CONNTRACK_HASH_TABLE_SIZE; i++)
{
while(!list_empty(&ct_table[i]))
{
entry = list_first(&ct_table[i]);
ctEntry = container_of(entry, struct ctTable, list);
__cmmCtRemove(ctEntry);
}
}
for (i = 0; i < FLOW_HASH_TABLE_SIZE; i++)
{
while (!list_empty(&flow_table[i]))
{
entry = list_first(&flow_table[i]);
FlowEntry = container_of(entry, struct FlowEntry, list);
__cmmFlowRemove(FlowEntry);
}
}
for (i = 0; i < 2 * ROUTE_HASH_TABLE_SIZE; i++)
{
while (!list_empty(&rt_table[i]))
{
entry = list_first(&rt_table[i]);
rtEntry = container_of(entry, struct RtEntry, list);
__cmmRouteRemove(rtEntry);
}
}
for (i = 0; i < 2 * NEIGHBOR_HASH_TABLE_SIZE; i++)
{
while (!list_empty(&neigh_table[i]))
{
entry = list_first(&neigh_table[i]);
neigh = container_of(entry, struct NeighborEntry, list);
__cmmNeighRemove(neigh);
}
}
for (i = 0; i < HASH_SOCKET_SIZE; i++)
{
while (!list_empty(&socket_table[i]))
{
entry = list_first(&socket_table[i]);
socket = container_of(entry, struct socket, list);
socket_remove(socket);
}
}
#ifdef AUTO_BRIDGE
__cmm_l2flow_reset(fci_handle);
#endif
unlock:
__pthread_mutex_unlock(&brMutex);
__pthread_mutex_unlock(&socket_lock);
__pthread_mutex_unlock(&flowMutex);
__pthread_mutex_unlock(&neighMutex);
__pthread_mutex_unlock(&rtMutex);
__pthread_mutex_unlock(&ctMutex);
__pthread_mutex_unlock(&itf_table.lock);
cmm_print(DEBUG_ERROR, "%s: end\n", __func__);
}
#ifdef AUTO_BRIDGE
static void cmmFeL2FlowChange(struct cmm_ct *ctx, fpp_l2_bridge_flow_entry_cmd_t* cmd, int len)
{
struct l2flow l2flow_tmp;
memset(&l2flow_tmp, 0 , sizeof(l2flow_tmp));
memcpy(l2flow_tmp.saddr, cmd->srcaddr, ETH_ALEN);
memcpy(l2flow_tmp.daddr, cmd->destaddr, ETH_ALEN);
l2flow_tmp.ethertype = cmd->ethertype;
l2flow_tmp.vlan_tag =cmd->vlan_tag;
l2flow_tmp.session_id = cmd->session_id;
l2flow_tmp.l3.proto = cmd->proto;
memcpy(l2flow_tmp.l3.saddr.all, cmd->saddr, 16);
memcpy(l2flow_tmp.l3.daddr.all, cmd->daddr, 16);
l2flow_tmp.l4.sport = cmd->sport;
l2flow_tmp.l4.dport = cmd->dport;
__pthread_mutex_lock(&brMutex);
__cmm_l2flow_deregister(ctx->fci_handle, &l2flow_tmp);
__pthread_mutex_unlock(&brMutex);
}
int cmmFeL2FlowUpdate(FCI_CLIENT* fci_handler, int request, struct l2flowTable *l2flow_entry)
{
int action;
short ret;
fpp_l2_bridge_flow_entry_cmd_t cmd;
memset(&cmd, 0, sizeof(cmd));
switch (request)
{
default:
case (ADD | UPDATE):
if ((l2flow_entry->flags & (FPP_PROGRAMMED | FPP_NEEDS_UPDATE)) == FPP_PROGRAMMED)
goto out;
if ((l2flow_entry->flags & (FPP_PROGRAMMED | FPP_NEEDS_UPDATE)) == (FPP_PROGRAMMED | FPP_NEEDS_UPDATE))
{
action = FPP_ACTION_UPDATE;
}
else
{
action = FPP_ACTION_REGISTER;
}
break;
case UPDATE:
if (!((l2flow_entry->flags & FPP_PROGRAMMED) && (l2flow_entry->flags & FPP_NEEDS_UPDATE)))
goto out;
action = FPP_ACTION_UPDATE;
break;
case REMOVE:
if (!(l2flow_entry->flags & FPP_PROGRAMMED))
goto out;
action = FPP_ACTION_DEREGISTER;
break;
}
if (action != FPP_ACTION_DEREGISTER)
{
if (__itf_get_name(l2flow_entry->idev_ifi, cmd.input_name, sizeof(cmd.input_name)) < 0)
{
cmm_print(DEBUG_ERROR, "%s: __itf_get_name(%d) failed\n", __func__, l2flow_entry->idev_ifi);
goto err;
}
if (__itf_get_name(l2flow_entry->odev_ifi, cmd.output_name, sizeof(cmd.output_name)) < 0)
{
cmm_print(DEBUG_ERROR, "%s: __itf_get_name(%d) failed\n", __func__, l2flow_entry->odev_ifi);
goto err;
}
}
cmd.action = action;
memcpy(cmd.destaddr, l2flow_entry->l2flow.daddr, ETH_ALEN);
memcpy(cmd.srcaddr, l2flow_entry->l2flow.saddr, ETH_ALEN);
cmd.ethertype = l2flow_entry->l2flow.ethertype;
cmd.vlan_tag = l2flow_entry->l2flow.vlan_tag;
cmd.session_id = l2flow_entry->l2flow.session_id;
cmd.proto = l2flow_entry->l2flow.l3.proto;
memcpy(cmd.saddr, l2flow_entry->l2flow.l3.saddr.all, 16);
memcpy(cmd.daddr, l2flow_entry->l2flow.l3.daddr.all, 16);
cmd.sport = l2flow_entry->l2flow.l4.sport;
cmd.dport = l2flow_entry->l2flow.l4.dport;
cmd.mark = l2flow_entry->mark;
cmm_print(DEBUG_INFO, "PROTO %d\n", cmd.proto);
switch (action)
{
case FPP_ACTION_REGISTER:
// Send message to forward engine
cmm_print(DEBUG_COMMAND, "Send FPP_CMD_RX_L2FLOW_ENTRY, ACTION_REGISTER\n");
ret = fci_write(fci_handler, FPP_CMD_RX_L2FLOW_ENTRY, sizeof(fpp_l2_bridge_flow_entry_cmd_t), (unsigned short *) &cmd);
if ((ret == FPP_ERR_OK) || (ret == FPP_ERR_BRIDGE_ENTRY_ALREADY_EXISTS)){
l2flow_entry->flags |= FPP_PROGRAMMED;
l2flow_entry->flags &= ~FPP_NEEDS_UPDATE;
}
else {
cmm_print(DEBUG_ERROR, "Error %d while sending FPP_CMD_RX_L2FLOW_ENTRY, ACTION_REGISTER\n", ret);
goto err;
}
break;
case FPP_ACTION_UPDATE:
// Send message to forward engine
cmm_print(DEBUG_COMMAND, "Send FPP_CMD_RX_L2FLOW_ENTRY, ACTION_REGISTER\n");
ret = fci_write(fci_handler, FPP_CMD_RX_L2FLOW_ENTRY, sizeof(fpp_l2_bridge_flow_entry_cmd_t), (unsigned short *) &cmd);
if (ret == FPP_ERR_OK){
l2flow_entry->flags &= ~FPP_NEEDS_UPDATE;
}
else {
cmm_print(DEBUG_ERROR, "Error %d while sending FPP_CMD_RX_L2FLOW_ENTRY, ACTION_UPDATE\n", ret);
goto err;
}
break;
case FPP_ACTION_DEREGISTER:
// Send message to forward engine
cmm_print(DEBUG_COMMAND, "Send FPP_CMD_RX_L2FLOW_ENTRY, ACTION_DEREGISTER\n");
ret = fci_write(fci_handler, FPP_CMD_RX_L2FLOW_ENTRY, sizeof(fpp_l2_bridge_flow_entry_cmd_t), (unsigned short *) &cmd);
if ((ret == FPP_ERR_OK) || (ret == FPP_ERR_BRIDGE_ENTRY_NOT_FOUND)){
l2flow_entry->flags &= ~FPP_PROGRAMMED;
}
else {
cmm_print(DEBUG_ERROR, "Error %d while sending FPP_CMD_RX_L2FLOW_ENTRY, ACTION_DEREGISTER\n", ret);
goto err;
}
break;
default:
break;
}
out:
return 0;
err:
return -1;
}
#endif
/*****************************************************************
* cmmFeCtUpdate4
*
*
******************************************************************/
int cmmFeCtUpdate4(FCI_CLIENT *fci_handler, int action, struct ctTable *ctEntry)
{
fpp_ct_ex_cmd_t cmd;
int cmd_size = sizeof(fpp_ct_cmd_t);
short ret;
char saddr_buf[INET_ADDRSTRLEN], daddr_buf[INET_ADDRSTRLEN];
memset(&cmd, 0, sizeof(cmd));
cmd.action = action;
cmd.protocol = nfct_get_attr_u8(ctEntry->ct, ATTR_ORIG_L4PROTO);
cmd.saddr = nfct_get_attr_u32(ctEntry->ct, ATTR_ORIG_IPV4_SRC);
cmd.daddr = nfct_get_attr_u32(ctEntry->ct, ATTR_ORIG_IPV4_DST);
cmd.saddr_reply = nfct_get_attr_u32(ctEntry->ct, ATTR_REPL_IPV4_SRC);
cmd.daddr_reply = nfct_get_attr_u32(ctEntry->ct, ATTR_REPL_IPV4_DST);
cmd.sport = nfct_get_attr_u16(ctEntry->ct, ATTR_ORIG_PORT_SRC);
cmd.dport = nfct_get_attr_u16(ctEntry->ct, ATTR_ORIG_PORT_DST);
cmd.sport_reply = nfct_get_attr_u16(ctEntry->ct, ATTR_REPL_PORT_SRC);
cmd.dport_reply = nfct_get_attr_u16(ctEntry->ct, ATTR_REPL_PORT_DST);
cmd.fwmark = nfct_get_attr_u32(ctEntry->ct, ATTR_MARK);
if (!(ctEntry->fpp_dir & ORIGINATOR))
cmd.flags |= CTCMD_FLAGS_ORIG_DISABLED;
if (!(ctEntry->fpp_dir & REPLIER))
cmd.flags |= CTCMD_FLAGS_REP_DISABLED;
cmm_print(DEBUG_INFO, "%s: protocol=%d, fwmark=0x%x\n", __func__, cmd.protocol, cmd.fwmark);
cmm_print(DEBUG_INFO, " Saddr=%s, Daddr=%s, Sport=%d, Dport=%d\n",
inet_ntop(AF_INET, &cmd.saddr, saddr_buf, sizeof(saddr_buf)),
inet_ntop(AF_INET, &cmd.daddr, daddr_buf, sizeof(daddr_buf)),
ntohs(cmd.sport), ntohs(cmd.dport));
cmm_print(DEBUG_INFO, " SaddrReply=%s, DaddrReply=%s, SportReply=%d, DportReply=%d\n",
inet_ntop(AF_INET, &cmd.saddr_reply, saddr_buf, sizeof(saddr_buf)),
inet_ntop(AF_INET, &cmd.daddr_reply, daddr_buf, sizeof(daddr_buf)),
ntohs(cmd.sport_reply), ntohs(cmd.dport_reply));
if (action != FPP_ACTION_DEREGISTER)
{
/**
* We must check to see if the queue and DSCP marking parameters were applied to the
* correct direction. When the connection was established, we assume that the orig
* direction is upstream (output port = WAN). If this is not true, then we must swap
* the queue and DSCP marking parameters with the twin connection.
*/
if ( (cmd.fwmark & 0x80000000) &&
(((ctEntry->fpp_dir & ORIGINATOR) &&
(is_wan_port_ifindex(nfct_get_attr_u32(ctEntry->ct, ATTR_ORIG_COMCERTO_FP_IIF)) &&
!is_wan_port_ifindex(ctEntry->orig.route->oifindex))) ||
((ctEntry->fpp_dir & REPLIER) &&
(!is_wan_port_ifindex(nfct_get_attr_u32(ctEntry->ct, ATTR_REPL_COMCERTO_FP_IIF)) &&
is_wan_port_ifindex(ctEntry->rep.route->oifindex))))
)
{
unsigned int fwmark_lo, fwmark_hi;
fwmark_lo = cmd.fwmark & 0xFFFF;
fwmark_hi = (cmd.fwmark >> 16) & 0xFFFF;
cmd.fwmark = ((fwmark_hi & 0x7fff) | (fwmark_lo & 0x8000)) | ((fwmark_lo & 0x7fff) << 16) | 0x80000000;
}
if (ctEntry->fEntryOrig)
{
cmd.format |= CT_SECURE;
cmd.sa_nr = ctEntry->fEntryOrig->sa_nr;
memcpy(cmd.sa_handle, ctEntry->fEntryOrig->sa_handle, ctEntry->fEntryOrig->sa_nr * sizeof(unsigned short));
}
if (ctEntry->fEntryRep)
{
cmd.format |= CT_SECURE;
cmd.sa_reply_nr = ctEntry->fEntryRep->sa_nr;
memcpy(cmd.sa_reply_handle, ctEntry->fEntryRep->sa_handle, ctEntry->fEntryRep->sa_nr * sizeof(unsigned short));
}
if (cmd.format & CT_SECURE)
{
cmm_print(DEBUG_INFO, "IPv4 conntrack secure Orig SAh(%d): %x Repl SAh(%d): %x\n",
cmd.sa_nr, cmd.sa_handle[0], cmd.sa_reply_nr, cmd.sa_reply_handle[0]);
cmd_size = sizeof(fpp_ct_ex_cmd_t);
}
if (ctEntry->orig_tunnel.fpp_route)
{
cmd.format |= CT_ORIG_TUNNEL_4o6;
cmd.tunnel_route_id = ctEntry->orig_tunnel.fpp_route_id;
}
if (ctEntry->rep_tunnel.fpp_route)
{
cmd.format |= CT_REPL_TUNNEL_4o6;
cmd.tunnel_route_id_reply = ctEntry->rep_tunnel.fpp_route_id;
}
if (cmd.format & (CT_ORIG_TUNNEL_4o6 | CT_REPL_TUNNEL_4o6))
cmd_size = sizeof(fpp_ct_ex_cmd_t);
cmd.route_id = ctEntry->orig.fpp_route_id;
cmd.route_id_reply = ctEntry->rep.fpp_route_id;
}
switch (action)
{
case FPP_ACTION_REGISTER:
// Send message to forward engine
cmm_print(DEBUG_COMMAND, "Send CMD_IPV4_CONNTRACK ACTION_REGISTER\n");
ret = fci_write(fci_handler, FPP_CMD_IPV4_CONNTRACK, cmd_size, (unsigned short *) &cmd);
if ((ret == FPP_ERR_OK) || (ret == FPP_ERR_CT_ENTRY_ALREADY_REGISTERED))
{
if (ctEntry->fEntryOrig)
{
ctEntry->fEntryOrig->flags |= FPP_PROGRAMMED;
ctEntry->fEntryOrig->flags &= ~FPP_NEEDS_UPDATE;
}
if (ctEntry->fEntryRep)
{
ctEntry->fEntryRep->flags |= FPP_PROGRAMMED;
ctEntry->fEntryRep->flags &= ~FPP_NEEDS_UPDATE;
}
ctEntry->flags |= FPP_PROGRAMMED;
ctEntry->flags &= ~FPP_NEEDS_UPDATE;
}
else
{
cmm_print(DEBUG_ERROR, "Error %d while sending CMD_IPV4_CONNTRACK, ACTION_REGISTER\n", ret);
goto err;
}
break;
case FPP_ACTION_UPDATE:
cmm_print(DEBUG_COMMAND, "Send CMD_IPV4_CONNTRACK ACTION_UPDATE\n");
ret = fci_write(fci_handler, FPP_CMD_IPV4_CONNTRACK, cmd_size, (unsigned short *) &cmd);
if (ret == FPP_ERR_OK)
{
if (ctEntry->fEntryOrig)
ctEntry->fEntryOrig->flags &= ~FPP_NEEDS_UPDATE;
if (ctEntry->fEntryRep)
ctEntry->fEntryRep->flags &= ~FPP_NEEDS_UPDATE;
ctEntry->flags &= ~FPP_NEEDS_UPDATE;
}
else
{
cmm_print(DEBUG_ERROR, "Error %d while sending CMD_IPV4_CONNTRACK, ACTION_UPDATE\n", ret);
goto err;
}
break;
case FPP_ACTION_DEREGISTER:
default:
// Send message to forward engine
cmm_print(DEBUG_COMMAND, "Send CMD_IPV4_CONNTRACK ACTION_DEREGISTER\n");
ret = fci_write(fci_handler, FPP_CMD_IPV4_CONNTRACK, sizeof(fpp_ct_cmd_t), (unsigned short *) &cmd);
if ((ret == FPP_ERR_OK) || (ret == FPP_ERR_CT_ENTRY_NOT_FOUND))
{
if (ctEntry->fEntryOrig)
ctEntry->fEntryOrig->flags &= ~FPP_PROGRAMMED;
if (ctEntry->fEntryRep)
ctEntry->fEntryRep->flags &= ~FPP_PROGRAMMED;
ctEntry->flags &= ~FPP_PROGRAMMED;
}
else
{
cmm_print(DEBUG_ERROR, "Error %d while sending CMD_IPV4_CONNTRACK, ACTION_DEREGISTER\n", ret);
goto err;
}
break;
}
return 0;
err:
return -1;
}
/*****************************************************************
* cmmFeCtUpdate6
*
*
******************************************************************/
int cmmFeCtUpdate6(FCI_CLIENT *fci_handler, int action, struct ctTable *ctEntry)
{
fpp_ct6_ex_cmd_t cmd;
int cmd_size = sizeof(fpp_ct6_cmd_t);
short ret;
char buf[INET6_ADDRSTRLEN], buf1[INET6_ADDRSTRLEN];
memset(&cmd, 0, sizeof(cmd));
cmd.action = action;
cmd.protocol = nfct_get_attr_u8(ctEntry->ct, ATTR_ORIG_L4PROTO);
memcpy(cmd.saddr, nfct_get_attr(ctEntry->ct, ATTR_ORIG_IPV6_SRC), 16);
memcpy(cmd.daddr, nfct_get_attr(ctEntry->ct, ATTR_ORIG_IPV6_DST), 16);
memcpy(cmd.saddr_reply, nfct_get_attr(ctEntry->ct, ATTR_REPL_IPV6_SRC), 16);
memcpy(cmd.daddr_reply, nfct_get_attr(ctEntry->ct, ATTR_REPL_IPV6_DST), 16);
cmd.sport = nfct_get_attr_u16(ctEntry->ct, ATTR_ORIG_PORT_SRC);
cmd.dport = nfct_get_attr_u16(ctEntry->ct, ATTR_ORIG_PORT_DST);
cmd.sport_reply = nfct_get_attr_u16(ctEntry->ct, ATTR_REPL_PORT_SRC);
cmd.dport_reply = nfct_get_attr_u16(ctEntry->ct, ATTR_REPL_PORT_DST);
cmd.fwmark = nfct_get_attr_u32(ctEntry->ct, ATTR_MARK);
cmd.route_id = ctEntry->orig.fpp_route_id;
cmd.route_id_reply = ctEntry->rep.fpp_route_id;
if (!(ctEntry->fpp_dir & ORIGINATOR))
cmd.flags |= CTCMD_FLAGS_ORIG_DISABLED;
if (!(ctEntry->fpp_dir & REPLIER))
cmd.flags |= CTCMD_FLAGS_REP_DISABLED;
cmm_print(DEBUG_INFO, "%s: protocol=%d, fwmark=0x%x\n", __func__, cmd.protocol, cmd.fwmark);
cmm_print(DEBUG_INFO, " Saddr=%s, Daddr=%s, Sport=%d, Dport=%d\n",
inet_ntop(AF_INET6, &cmd.saddr, buf, sizeof(buf)),
inet_ntop(AF_INET6, &cmd.daddr, buf1, sizeof(buf1)),
ntohs(cmd.sport), ntohs(cmd.dport));
cmm_print(DEBUG_INFO, " SaddrReply=%s, DaddrReply=%s, SportReply=%d, DportReply=%d\n",
inet_ntop(AF_INET6, &cmd.saddr_reply, buf, sizeof(buf)),
inet_ntop(AF_INET6, &cmd.daddr_reply, buf1, sizeof(buf1)),
ntohs(cmd.sport_reply), ntohs(cmd.dport_reply));
if (action != FPP_ACTION_DEREGISTER)
{
/**
* We must check to see if the queue and DSCP marking parameters were applied to the
* correct direction. When the connection was established, we assume that the orig
* direction is upstream (output port = WAN). If this is not true, then we must swap
* the queue and DSCP marking parameters with the twin connection.
*/
if ( (cmd.fwmark & 0x80000000) &&
(((ctEntry->fpp_dir & ORIGINATOR) &&
(is_wan_port_ifindex(nfct_get_attr_u32(ctEntry->ct, ATTR_ORIG_COMCERTO_FP_IIF)) &&
!is_wan_port_ifindex(ctEntry->orig.route->oifindex))) ||
((ctEntry->fpp_dir & REPLIER) &&
(!is_wan_port_ifindex(nfct_get_attr_u32(ctEntry->ct, ATTR_REPL_COMCERTO_FP_IIF)) &&
is_wan_port_ifindex(ctEntry->rep.route->oifindex))))
)
{
unsigned int fwmark_lo, fwmark_hi;
fwmark_lo = cmd.fwmark & 0xFFFF;
fwmark_hi = (cmd.fwmark >> 16) & 0xFFFF;
cmd.fwmark = ((fwmark_hi & 0x7fff) | (fwmark_lo & 0x8000)) | ((fwmark_lo & 0x7fff) << 16) | 0x80000000;
}
if (ctEntry->fEntryOrig) {
cmd.format |= CT_SECURE;
cmd.sa_nr = ctEntry->fEntryOrig->sa_nr;
memcpy(cmd.sa_handle, ctEntry->fEntryOrig->sa_handle, ctEntry->fEntryOrig->sa_nr * sizeof(unsigned short));
}
if (ctEntry->fEntryRep) {
cmd.format |= CT_SECURE;
cmd.sa_reply_nr = ctEntry->fEntryRep->sa_nr;
memcpy(cmd.sa_reply_handle, ctEntry->fEntryRep->sa_handle, ctEntry->fEntryRep->sa_nr * sizeof(unsigned short));
}
if (cmd.format & CT_SECURE) {
cmm_print(DEBUG_INFO, "IPv6 conntrack secure Orig SAh(%d): %x Repl SAh(%d): %x\n",
cmd.sa_nr, cmd.sa_handle[0], cmd.sa_reply_nr, cmd.sa_reply_handle[0]);
cmd_size = sizeof(fpp_ct6_ex_cmd_t);
}
if (ctEntry->orig_tunnel.fpp_route)
{
cmd.format |= CT_ORIG_TUNNEL_SIT;
cmd.tunnel_route_id = ctEntry->orig_tunnel.fpp_route_id;
}
if (ctEntry->rep_tunnel.fpp_route)
{
cmd.format |= CT_REPL_TUNNEL_SIT;
cmd.tunnel_route_id_reply = ctEntry->rep_tunnel.fpp_route_id;
}
if (cmd.format & (CT_ORIG_TUNNEL_SIT | CT_REPL_TUNNEL_SIT)) {
cmm_print(DEBUG_INFO, "IPv6 tunnel route id orig(%x) repl(%x)\n",
cmd.tunnel_route_id,
cmd.tunnel_route_id_reply);
cmd_size = sizeof(fpp_ct6_ex_cmd_t);
}
}
switch (action)
{
case FPP_ACTION_REGISTER:
// Send message to forward engine
cmm_print(DEBUG_COMMAND, "Send CMD_IPV6_CONNTRACK ACTION_REGISTER\n");
ret = fci_write(fci_handler, FPP_CMD_IPV6_CONNTRACK, cmd_size, (unsigned short *) &cmd);
if ((ret == FPP_ERR_OK) || (ret == FPP_ERR_CT_ENTRY_ALREADY_REGISTERED))
{
if (ctEntry->fEntryOrig)
{
ctEntry->fEntryOrig->flags |= FPP_PROGRAMMED;
ctEntry->fEntryOrig->flags &= ~FPP_NEEDS_UPDATE;
}
if (ctEntry->fEntryRep)
{
ctEntry->fEntryRep->flags |= FPP_PROGRAMMED;
ctEntry->fEntryRep->flags &= ~FPP_NEEDS_UPDATE;
}
ctEntry->flags |= FPP_PROGRAMMED;
ctEntry->flags &= ~FPP_NEEDS_UPDATE;
}
else
{
cmm_print(DEBUG_ERROR, "Error %d while sending CMD_IPV6_CONNTRACK, ACTION_REGISTER\n", ret);
goto err;
}
break;
case FPP_ACTION_UPDATE:
cmm_print(DEBUG_COMMAND, "Send CMD_IPV6_CONNTRACK ACTION_UPDATE\n");
ret = fci_write(fci_handler, FPP_CMD_IPV6_CONNTRACK, cmd_size, (unsigned short *) &cmd);
if (ret == FPP_ERR_OK)
{
if (ctEntry->fEntryOrig)
ctEntry->fEntryOrig->flags &= ~FPP_NEEDS_UPDATE;
if (ctEntry->fEntryRep)
ctEntry->fEntryRep->flags &= ~FPP_NEEDS_UPDATE;
ctEntry->flags &= ~FPP_NEEDS_UPDATE;
}
else
{
cmm_print(DEBUG_ERROR, "Error %d while sending CMD_IPV6_CONNTRACK, ACTION_UPDATE\n", ret);
goto err;
}
break;
case FPP_ACTION_DEREGISTER:
default:
// Send message to forward engine
cmm_print(DEBUG_COMMAND, "Send CMD_IPV6_CONNTRACK ACTION_DEREGISTER\n");
ret = fci_write(fci_handler, FPP_CMD_IPV6_CONNTRACK, sizeof(fpp_ct6_cmd_t), (unsigned short *) &cmd);
if ((ret == FPP_ERR_OK) || (ret == FPP_ERR_CT_ENTRY_NOT_FOUND))
{
if (ctEntry->fEntryOrig)
ctEntry->fEntryOrig->flags &= ~FPP_PROGRAMMED;
if (ctEntry->fEntryRep)
ctEntry->fEntryRep->flags &= ~FPP_PROGRAMMED;
ctEntry->flags &= ~FPP_PROGRAMMED;
}
else
{
cmm_print(DEBUG_ERROR, "Error %d while sending CMD_IPV6_CONNTRACK, ACTION_DEREGISTER\n", ret);
goto err;
}
break;
}
return 0;
err:
return -1;
}
/*****************************************************************
* cmmFeCtChange4
*
*
******************************************************************/
static void cmmFeCtChange4(struct cmm_ct *ctx, fpp_ct_cmd_t* cmd, int len)
{
struct nf_conntrack *ctTemp;
struct ctTable *ctEntry;
if (len < sizeof(fpp_ct_cmd_t))
{
cmm_print(DEBUG_ERROR, "%s: wrong length(%d) CMD_IPV4_CONNTRACK_CHANGE\n", __func__, len);
return;
}
ctTemp = nfct_new();
nfct_set_attr_u8(ctTemp, ATTR_ORIG_L4PROTO, cmd->protocol);
nfct_set_attr_u8(ctTemp, ATTR_ORIG_L3PROTO, AF_INET);
nfct_set_attr_u32(ctTemp, ATTR_ORIG_IPV4_SRC, cmd->saddr);
nfct_set_attr_u32(ctTemp, ATTR_ORIG_IPV4_DST, cmd->daddr);
nfct_set_attr_u32(ctTemp, ATTR_REPL_IPV4_SRC, cmd->saddr_reply);
nfct_set_attr_u32(ctTemp, ATTR_REPL_IPV4_DST, cmd->daddr_reply);
nfct_set_attr_u16(ctTemp, ATTR_ORIG_PORT_SRC, cmd->sport);
nfct_set_attr_u16(ctTemp, ATTR_ORIG_PORT_DST, cmd->dport);
nfct_set_attr_u16(ctTemp, ATTR_REPL_PORT_SRC, cmd->sport_reply);
nfct_set_attr_u16(ctTemp, ATTR_REPL_PORT_DST, cmd->dport_reply);
__pthread_mutex_lock(&itf_table.lock);
__pthread_mutex_lock(&ctMutex);
switch (cmd->action)
{
case FPP_ACTION_REMOVED:
// We have to remove the conntrack in the conntrack table
if (!(ctEntry = __cmmCtFind(ctTemp)))
{
cmm_print(DEBUG_WARNING, "%s: conntrack not found\n", __func__);
goto end;
}
cmm_print(DEBUG_COMMAND, "%s: CMD_IPV4_CONNTRACK_CHANGE, ACTION_REMOVED\n", __func__);
ctEntry->flags &= ~FPP_PROGRAMMED;
cmmCtNetlinkRemove(ctx->handle, ctEntry->ct);
ct_stats.removed++;
____cmmCtDeregister(ctx->fci_handle, ctx->fci_key_handle, ctEntry);
break;
case FPP_ACTION_TCP_FIN:
// We have to remove the conntrack in the conntrack table
if (!(ctEntry = __cmmCtFind(ctTemp)))
{
cmm_print(DEBUG_WARNING, "%s: conntrack not found\n", __func__);
goto end;
}
cmm_print(DEBUG_COMMAND, "%s: CMD_IPV4_CONNTRACK_CHANGE, ACTION_TCP_FIN\n", __func__);
ctEntry->flags &= ~FPP_PROGRAMMED;
break;
default:
cmm_print(DEBUG_ERROR, "%s: unsupported action(%d) for CMD_IPV4_CONNTRACK_CHANGE\n", __func__, cmd->action);
break;
}
end:
__pthread_mutex_unlock(&ctMutex);
__pthread_mutex_unlock(&itf_table.lock);
nfct_destroy(ctTemp);
}
/*****************************************************************
* cmmFeCtChange6
*
*
******************************************************************/
static void cmmFeCtChange6(struct cmm_ct *ctx, fpp_ct6_cmd_t* cmd, int len)
{
struct nf_conntrack *ctTemp;
struct ctTable *ctEntry;
if (len < sizeof(fpp_ct6_cmd_t))
{
cmm_print(DEBUG_ERROR, "%s: wrong length(%d) CMD_IPV6_CONNTRACK_CHANGE\n", __func__, len);
return;
}
ctTemp = nfct_new();
nfct_set_attr_u8(ctTemp, ATTR_ORIG_L4PROTO, cmd->protocol);
nfct_set_attr_u8(ctTemp, ATTR_ORIG_L3PROTO, AF_INET6);
nfct_set_attr(ctTemp, ATTR_ORIG_IPV6_SRC, &cmd->saddr[0]);
nfct_set_attr(ctTemp, ATTR_ORIG_IPV6_DST, &cmd->daddr[0]);
nfct_set_attr(ctTemp, ATTR_REPL_IPV6_SRC, &cmd->saddr_reply[0]);
nfct_set_attr(ctTemp, ATTR_REPL_IPV6_DST, &cmd->daddr_reply[0]);
nfct_set_attr_u16(ctTemp, ATTR_ORIG_PORT_SRC, cmd->sport);
nfct_set_attr_u16(ctTemp, ATTR_ORIG_PORT_DST, cmd->dport);
nfct_set_attr_u16(ctTemp, ATTR_REPL_PORT_SRC, cmd->sport_reply);
nfct_set_attr_u16(ctTemp, ATTR_REPL_PORT_DST, cmd->dport_reply);
__pthread_mutex_lock(&itf_table.lock);
__pthread_mutex_lock(&ctMutex);
switch(cmd->action)
{
case FPP_ACTION_REMOVED:
// We have to remove the conntrack in the local table and also the one in the conntrack table
if (!(ctEntry = __cmmCtFind(ctTemp)))
{
cmm_print(DEBUG_WARNING, "%s: conntrack not found\n", __func__);
goto end;
}
cmm_print(DEBUG_COMMAND, "%s: CMD_IPV6_CONNTRACK_CHANGE, ACTION_REMOVED\n", __func__);
ctEntry->flags &= ~FPP_PROGRAMMED;
cmmCtNetlinkRemove(ctx->handle, ctEntry->ct);
ct_stats.removed++;
____cmmCtDeregister(ctx->fci_handle, ctx->fci_key_handle, ctEntry);
break;
case FPP_ACTION_TCP_FIN:
// We have to remove the conntrack in the conntrack table
if (!(ctEntry = __cmmCtFind(ctTemp)))
{
cmm_print(DEBUG_WARNING, "%s: conntrack not found\n", __func__);
goto end;
}
cmm_print(DEBUG_COMMAND, "%s: CMD_IPV6_CONNTRACK_CHANGE, ACTION_TCP_FIN\n", __func__);
ctEntry->flags &= ~FPP_PROGRAMMED;
break;
default:
cmm_print(DEBUG_ERROR, "%s: unsupported action(%d) for CMD_IPV6_CONNTRACK_CHANGE\n", __func__, cmd->action);
break;
}
end:
__pthread_mutex_unlock(&ctMutex);
__pthread_mutex_unlock(&itf_table.lock);
nfct_destroy(ctTemp);
}
/*****************************************************************
* __cmmFeRouteUpdate
*
*
******************************************************************/
int __cmmFeRouteUpdate(FCI_CLIENT* fci_handler, int action, struct fpp_rt *fpp_route)
{
fpp_rt_cmd_t cmd;
short ret;
memset(&cmd, 0, sizeof(cmd));
cmd.action = action;
cmd.id = fpp_route->id;
if (action != FPP_ACTION_DEREGISTER)
{
memcpy(&cmd.dst_mac, fpp_route->dst_mac, 6);
if (fpp_route->dst_addr_len) {
if(fpp_route->dst_addr_len == 4 ) /* IPv4 Address Size */
cmd.flags |= FPP_IP_ROUTE_6o4;
else if(fpp_route->dst_addr_len == 16) /* IPv6 Address Size */
cmd.flags |= FPP_IP_ROUTE_4o6;
memcpy(&cmd.dst_addr, fpp_route->dst_addr, fpp_route->dst_addr_len);
}
if (__itf_get_name(fpp_route->oifindex, cmd.output_device, sizeof(cmd.output_device)) < 0)
{
cmm_print(DEBUG_ERROR, "%s: __itf_get_name(%d) failed\n", __func__, fpp_route->oifindex);
goto err;
}
cmd.mtu = fpp_route->mtu;
}
switch (action)
{
case FPP_ACTION_REGISTER:
cmm_print(DEBUG_COMMAND, "Send CMD_IP_ROUTE ACTION_REGISTER\n");
ret = fci_write(fci_handler, FPP_CMD_IP_ROUTE, sizeof(fpp_rt_cmd_t), (unsigned short *)&cmd);
if ((ret == FPP_ERR_OK) || (ret == FPP_ERR_RT_ENTRY_ALREADY_REGISTERED))
{
fpp_route->flags |= FPP_PROGRAMMED;
fpp_route->flags &= ~FPP_NEEDS_UPDATE;
}
else
{
cmm_print(DEBUG_ERROR, "Error %d while sending CMD_IP_ROUTE, ACTION_REGISTER\n", ret);
goto err;
}
break;
case FPP_ACTION_UPDATE:
cmm_print(DEBUG_COMMAND, "Send CMD_IP_ROUTE ACTION_UPDATE\n");
ret = fci_write(fci_handler, FPP_CMD_IP_ROUTE, sizeof(fpp_rt_cmd_t), (unsigned short *)&cmd);
if (ret == FPP_ERR_OK)
{
fpp_route->flags &= ~FPP_NEEDS_UPDATE;
}
else
{
cmm_print(DEBUG_ERROR, "Error %d while sending CMD_IP_ROUTE, ACTION_UPDATE\n", ret);
goto err;
}
break;
case FPP_ACTION_DEREGISTER:
default:
cmm_print(DEBUG_COMMAND, "Send CMD_IP_ROUTE ACTION_DEREGISTER\n");
ret = fci_write(fci_handler, FPP_CMD_IP_ROUTE, sizeof(fpp_rt_cmd_t), (unsigned short *)&cmd);
if ((ret == FPP_ERR_OK) || (ret == FPP_ERR_RT_ENTRY_NOT_FOUND))
{
fpp_route->flags &= ~FPP_PROGRAMMED;
}
else
{
cmm_print(DEBUG_ERROR, "Error %d while sending CMD_IP_ROUTE, ACTION_DEREGISTER\n", ret);
goto err;
}
break;
}
return 0;
err:
return -1;
}
/*****************************************************************
* cmmRtQueryProcess
*
*
******************************************************************/
int cmmRtQueryProcess(char ** keywords, int tabStart, daemon_handle_t daemon_handle)
{
int rcvBytes;
char rcvBuffer[256];
short rc;
int count = 0;
char dmac[MAC_ADDRSTRLEN];
fpp_rt_cmd_t *rtCmd = (fpp_rt_cmd_t *)rcvBuffer;
rtCmd->action = FPP_ACTION_QUERY;
rcvBytes = cmmSendToDaemon(daemon_handle, FPP_CMD_IP_ROUTE, rtCmd, sizeof(fpp_rt_cmd_t), rcvBuffer);
if (rcvBytes < sizeof(fpp_rt_cmd_t) + sizeof(unsigned short)) {
rc = (rcvBytes < sizeof(unsigned short) ) ? 0 : *((unsigned short *) rcvBuffer);
if (rc == FPP_ERR_UNKNOWN_ACTION) {
cmm_print(DEBUG_STDERR, "ERROR: FPP_CMD_IP_ROUTE does not support ACTION_QUERY\n");
} else if (rc == FPP_ERR_RT_ENTRY_NOT_FOUND) {
cmm_print(DEBUG_STDERR, "ERROR: FPP IP ROUTE table empty\n");
} else {
cmm_print(DEBUG_STDERR, "ERROR: Unexpected result returned from FPP rc:%d\n", rc);
}
return CLI_OK;
}
cmm_print(DEBUG_STDOUT, "IP ROUTE:\n");
do {
rtCmd->output_device[11] = '\0';
cmm_print(DEBUG_STDOUT, "%04d: Id: %x, Interface: %s, DST Mac: %s, Mtu: %d\n",
count,
rtCmd->id,
rtCmd->output_device,
mac_ntop(rtCmd->dst_mac, dmac, sizeof(dmac)),
rtCmd->mtu);
count++;
rtCmd->action = FPP_ACTION_QUERY_CONT;
rcvBytes = cmmSendToDaemon(daemon_handle, FPP_CMD_IP_ROUTE, rtCmd, sizeof(fpp_rt_cmd_t), rcvBuffer);
} while (rcvBytes >= sizeof(fpp_rt_cmd_t) + sizeof(unsigned short));
cmm_print(DEBUG_STDOUT, "Total FPP Route Entries: %d\n", count);
return CLI_OK;
}
/*****************************************************************
* cmmCtQueryProcess
*
*
******************************************************************/
int cmmCtQueryProcess(char ** keywords, int tabStart, daemon_handle_t daemon_handle)
{
int rcvBytes = 0;
char rcvBuffer[256];
char output_buf[256];
short rc;
int count = 0,i,len =0;
cmmd_ct_ex_cmd_t *ctCmd = (cmmd_ct_ex_cmd_t *)rcvBuffer;
struct nf_conntrack *ctTemp;
char saddr_buf[INET_ADDRSTRLEN], daddr_buf[INET_ADDRSTRLEN];
ctCmd->action = CMMD_ACTION_QUERY;
ctCmd->format = 0;
ctCmd->sa_nr = 0;
ctCmd->sa_reply_nr = 0;
rcvBytes = cmmSendToDaemon(daemon_handle, CMMD_CMD_IPV4_CONNTRACK, ctCmd, sizeof(cmmd_ct_ex_cmd_t), rcvBuffer);
if (rcvBytes < sizeof(cmmd_ct_ex_cmd_t) + sizeof(unsigned short)) {
rc = (rcvBytes < sizeof(unsigned short) ) ? 0 : *((unsigned short *) rcvBuffer);
if (rc == FPP_ERR_UNKNOWN_ACTION) {
cmm_print(DEBUG_STDERR, "ERROR: FPP CMM_IPV4_CONNTRACK does not support ACTION_QUERY\n");
} else if (rc == FPP_ERR_CT_ENTRY_NOT_FOUND) {
cmm_print(DEBUG_STDERR, "ERROR: FPP IPV4 CONNTRACK table empty\n");
} else {
cmm_print(DEBUG_STDERR, "ERROR: Unexpected result returned from FPP rc:%d\n", rc);
}
return CLI_OK;
}
ctTemp = nfct_new();
cmm_print(DEBUG_STDOUT, "IPv4 Connections:\n");
do {
nfct_set_attr_u8(ctTemp, ATTR_ORIG_L4PROTO, ctCmd->protocol);
nfct_set_attr_u32(ctTemp, ATTR_ORIG_IPV4_SRC, ctCmd->saddr);
nfct_set_attr_u32(ctTemp, ATTR_ORIG_IPV4_DST, ctCmd->daddr);
nfct_set_attr_u32(ctTemp, ATTR_REPL_IPV4_SRC, ctCmd->saddr_reply);
nfct_set_attr_u32(ctTemp, ATTR_REPL_IPV4_DST, ctCmd->daddr_reply);
nfct_set_attr_u16(ctTemp, ATTR_ORIG_PORT_SRC, ctCmd->sport);
nfct_set_attr_u16(ctTemp, ATTR_ORIG_PORT_DST, ctCmd->dport);
nfct_set_attr_u16(ctTemp, ATTR_REPL_PORT_SRC, ctCmd->sport_reply);
nfct_set_attr_u16(ctTemp, ATTR_REPL_PORT_DST, ctCmd->dport_reply);
nfct_set_attr_u32(ctTemp, ATTR_MARK, ctCmd->fwmark);
//nfct_snprintf(buf, 500, ctTemp, NFCT_T_UNKNOWN, NFCT_O_PLAIN, NFCT_OF_SHOW_LAYER3);
//cmm_print(DEBUG_STDOUT, "%04d: %s\n", count, buf);
cmm_print(DEBUG_STDOUT, "%04d: protocol=%d, fwmark=0x%x\n", count, ctCmd->protocol, ctCmd->fwmark);
cmm_print(DEBUG_STDOUT, " Init: Saddr=%s, Daddr=%s, Sport=%d, Dport=%d\n",
inet_ntop(AF_INET, &ctCmd->saddr, saddr_buf, sizeof(saddr_buf)),
inet_ntop(AF_INET, &ctCmd->daddr, daddr_buf, sizeof(daddr_buf)),
ntohs(ctCmd->sport), ntohs(ctCmd->dport));
cmm_print(DEBUG_STDOUT, " Reply: Saddr=%s, Daddr=%s, Sport=%d, Dport=%d\n",
inet_ntop(AF_INET, &ctCmd->saddr_reply, saddr_buf, sizeof(saddr_buf)),
inet_ntop(AF_INET, &ctCmd->daddr_reply, daddr_buf, sizeof(daddr_buf)),
ntohs(ctCmd->sport_reply), ntohs(ctCmd->dport_reply));
if (ctCmd->format)
{
len += snprintf(output_buf+len,256-len, "IPSEC(Init:sa_nr=%d HO:",
ctCmd->sa_nr);
for (i =0; i< ctCmd->sa_nr;i++)
len += snprintf(output_buf+len ,256-len, "%x:", ctCmd->sa_handle[i]);
len += snprintf(output_buf+len,256-len,") ");
len += snprintf(output_buf+len, 256-len,"(Reply:sa_nr=%d HO:",
ctCmd->sa_reply_nr);
for (i =0; i< ctCmd->sa_reply_nr;i++)
len += snprintf(output_buf+len ,256-len,"%x:",
ctCmd->sa_reply_handle[i]);
len += snprintf(output_buf+len,256-len,") ");
cmm_print(DEBUG_STDOUT,"%s",output_buf);
len = 0;
}
count++;
ctCmd->action = CMMD_ACTION_QUERY_CONT;
ctCmd->format = 0;
ctCmd->sa_nr = 0;
ctCmd->sa_reply_nr = 0;
rcvBytes = cmmSendToDaemon(daemon_handle, CMMD_CMD_IPV4_CONNTRACK, ctCmd, sizeof(cmmd_ct_ex_cmd_t), rcvBuffer);
} while (rcvBytes >= sizeof(cmmd_ct_ex_cmd_t) + sizeof(unsigned short));
cmm_print(DEBUG_STDOUT, "Total Connection Entries: %d\n", count);
nfct_destroy(ctTemp);
return CLI_OK;
}
/*****************************************************************
* * cmmCt6QueryProcess
* *
* *
* ******************************************************************/
int cmmCt6QueryProcess(char ** keywords, int tabStart, daemon_handle_t daemon_handle)
{
int rcvBytes = 0;
char rcvBuffer[256];
char output_buf[256];
short rc;
int count = 0,len=0;
cmmd_ct6_ex_cmd_t *ctCmd = (cmmd_ct6_ex_cmd_t *)rcvBuffer;
struct nf_conntrack *ctTemp;
char saddr_buf[INET6_ADDRSTRLEN], daddr_buf[INET6_ADDRSTRLEN];
ctCmd->action = CMMD_ACTION_QUERY;
ctCmd->format = 0;
ctCmd->sa_nr = 0;
ctCmd->sa_reply_nr = 0;
rcvBytes = cmmSendToDaemon(daemon_handle, CMMD_CMD_IPV6_CONNTRACK, ctCmd,
sizeof(cmmd_ct6_ex_cmd_t), rcvBuffer);
if (rcvBytes < sizeof(cmmd_ct6_ex_cmd_t) + sizeof(unsigned short)) {
rc = (rcvBytes < sizeof(unsigned short) ) ? 0 :
*((unsigned short *) rcvBuffer);
if (rc == CMMD_ERR_UNKNOWN_ACTION) {
cmm_print(DEBUG_STDERR,
"ERROR: FPP CMM_IPV6_CONNTRACK does not support ACTION_QUERY\n");
} else if (rc == FPP_ERR_CT_ENTRY_NOT_FOUND) {
cmm_print(DEBUG_STDERR, "ERROR: FPP IPV6 CONNTRACK table empty\n");
} else {
cmm_print(DEBUG_STDERR,
"ERROR: Unexpected result returned from FPP rc:%d\n", rc);
}
return CLI_OK;
}
ctTemp = nfct_new();
cmm_print(DEBUG_STDOUT, "IPv6 Connections:\n");
do {
nfct_set_attr_u8(ctTemp, ATTR_ORIG_L4PROTO, ctCmd->protocol);
nfct_set_attr(ctTemp, ATTR_ORIG_IPV6_SRC, &ctCmd->saddr[0]);
nfct_set_attr(ctTemp, ATTR_ORIG_IPV6_DST, &ctCmd->daddr[0]);
nfct_set_attr(ctTemp, ATTR_REPL_IPV6_SRC, &ctCmd->saddr_reply[0]);
nfct_set_attr(ctTemp, ATTR_REPL_IPV6_DST, &ctCmd->daddr_reply[0]);
nfct_set_attr_u16(ctTemp, ATTR_ORIG_PORT_SRC, ctCmd->sport);
nfct_set_attr_u16(ctTemp, ATTR_ORIG_PORT_DST, ctCmd->dport);
nfct_set_attr_u16(ctTemp, ATTR_REPL_PORT_SRC, ctCmd->sport_reply);
nfct_set_attr_u16(ctTemp, ATTR_REPL_PORT_DST, ctCmd->dport_reply);
nfct_set_attr_u32(ctTemp, ATTR_MARK, ctCmd->fwmark);
cmm_print(DEBUG_STDOUT, "%04d: protocol=%d, fwmark=0x%x\n",
count, ctCmd->protocol, ctCmd->fwmark);
cmm_print(DEBUG_STDOUT, " Init: Saddr=%s, Daddr=%s, Sport=%d, Dport=%d\n",
inet_ntop(AF_INET6, &ctCmd->saddr, saddr_buf, sizeof(saddr_buf)),
inet_ntop(AF_INET6, &ctCmd->daddr, daddr_buf, sizeof(daddr_buf)),
ntohs(ctCmd->sport), ntohs(ctCmd->dport));
cmm_print(DEBUG_STDOUT, " Reply: Saddr=%s, Daddr=%s, Sport=%d, Dport=%d\n",
inet_ntop(AF_INET6, &ctCmd->saddr_reply, saddr_buf, sizeof(saddr_buf)),
inet_ntop(AF_INET6, &ctCmd->daddr_reply, daddr_buf, sizeof(daddr_buf)),
ntohs(ctCmd->sport_reply), ntohs(ctCmd->dport_reply));
if (ctCmd->format & CT_SECURE)
{
int i;
len += snprintf(output_buf+len, 256-len,"IPSEC(Init:sa_nr=%d HO:",ctCmd->sa_nr);
for (i =0; i< ctCmd->sa_nr;i++)
len += snprintf(output_buf+len ,256-len,"%x:", ctCmd->sa_handle[i]);
len += snprintf(output_buf+len,256-len,") ");
len += snprintf(output_buf+len,256-len," (Reply: sa_nr=%d HO:",
ctCmd->sa_reply_nr);
for (i =0; i< ctCmd->sa_reply_nr;i++)
len += snprintf(output_buf+len,256-len,"%x:",
ctCmd->sa_reply_handle[i]);
len += snprintf(output_buf+len,256-len,") ");
cmm_print(DEBUG_STDOUT,output_buf);
len = 0;
}
count++;
ctCmd->action = CMMD_ACTION_QUERY_CONT;
ctCmd->format = 0;
ctCmd->sa_nr = 0;
ctCmd->sa_reply_nr = 0;
rcvBytes = cmmSendToDaemon(daemon_handle, CMMD_CMD_IPV6_CONNTRACK, ctCmd,
sizeof(cmmd_ct6_ex_cmd_t), rcvBuffer);
} while (rcvBytes >= sizeof(cmmd_ct6_ex_cmd_t) + sizeof(unsigned short));
cmm_print(DEBUG_STDOUT, "Total Connection Entries: %d\n", count);
nfct_destroy(ctTemp);
return CLI_OK;
}
#ifdef AUTO_BRIDGE
/*****************************************************************
* cmmCtQueryProcess
*
*
******************************************************************/
int cmmL2FlowQueryProcess(char ** keywords, int tabStart, daemon_handle_t daemon_handle)
{
int rcvBytes = 0;
char rcvBuffer[256];
short rc;
int count = 0;
fpp_l2_bridge_flow_entry_cmd_t*cmd = (fpp_l2_bridge_flow_entry_cmd_t *)rcvBuffer;
cmd->action = FPP_ACTION_QUERY;
rcvBytes = cmmSendToDaemon(daemon_handle, FPP_CMD_RX_L2FLOW_ENTRY, cmd, sizeof(fpp_l2_bridge_flow_entry_cmd_t), rcvBuffer);
if (rcvBytes < sizeof(fpp_l2_bridge_flow_entry_cmd_t) + sizeof(unsigned short)) {
rc = (rcvBytes < sizeof(unsigned short) ) ? 0 : *((unsigned short *) rcvBuffer);
if (rc == FPP_ERR_UNKNOWN_ACTION) {
cmm_print(DEBUG_STDERR, "ERROR: FPP_CMD_RX_L2FLOW_ENTRY does not support ACTION_QUERY\n");
} else if (rc == FPP_ERR_BRIDGE_ENTRY_NOT_FOUND) {
cmm_print(DEBUG_STDERR, "ERROR: FPP L2flow table empty\n");
} else {
cmm_print(DEBUG_STDERR, "ERROR: Unexpected result returned from FPP rc:%d\n", rc);
}
return CLI_OK;
}
cmm_print(DEBUG_STDOUT, "L2 flows:\n");
do {
struct l2flow l2flow_tmp;
memset(&l2flow_tmp, 0 , sizeof(l2flow_tmp));
memcpy(l2flow_tmp.saddr, cmd->srcaddr, ETH_ALEN);
memcpy(l2flow_tmp.daddr, cmd->destaddr, ETH_ALEN);
l2flow_tmp.ethertype = cmd->ethertype;
l2flow_tmp.vlan_tag =cmd->vlan_tag;
l2flow_tmp.session_id = cmd->session_id;
l2flow_tmp.l3.proto = cmd->proto;
memcpy(l2flow_tmp.l3.saddr.all, cmd->saddr, 16);
memcpy(l2flow_tmp.l3.daddr.all, cmd->daddr, 16);
l2flow_tmp.l4.sport = cmd->sport;
l2flow_tmp.l4.dport = cmd->dport;
cmm_l2flow_print(DEBUG_STDOUT, &l2flow_tmp, 0);
cmm_print(DEBUG_STDOUT, "Input itf=%s ", cmd->input_name);
cmm_print(DEBUG_STDOUT, "Output itf=%s ", cmd->output_name);
cmm_print(DEBUG_STDOUT, "Timeout=%d s \n", cmd->timeout);
count++;
cmd->action = FPP_ACTION_QUERY_CONT;
rcvBytes = cmmSendToDaemon(daemon_handle, FPP_CMD_RX_L2FLOW_ENTRY, cmd, sizeof(fpp_l2_bridge_flow_entry_cmd_t), rcvBuffer);
} while (rcvBytes >= sizeof(cmmd_ct_ex_cmd_t) + sizeof(unsigned short));
cmm_print(DEBUG_STDOUT, "Total Flow Entries: %d\n", count);
return CLI_OK;
}
#endif
int cmmFeFFControl(FCI_CLIENT* fci_handler, u_int8_t *cmd_buf, u_int16_t cmd_len, u_int16_t *res_buf, u_int16_t *res_len)
{
fpp_ff_ctrl_cmd_t * cmd = (fpp_ff_ctrl_cmd_t *) cmd_buf;
int ret = 0;
res_buf[0] = CMMD_ERR_OK;
*res_len = 2;
if(cmd->enable)
{
if(!globalConf.ff_enable)
{
cmd->enable = 1;
// Send message to forward engine
cmm_print(DEBUG_COMMAND, "Send CMD_IPV4_FF_CONTROL cmd len=%d\n",sizeof(fpp_ff_ctrl_cmd_t));
ret = fci_cmd(fci_handler, FPP_CMD_IPV4_FF_CONTROL, (unsigned short *) cmd, sizeof(fpp_ff_ctrl_cmd_t), res_buf, res_len);
if (ret !=0 || res_buf[0] != FPP_ERR_OK)
{
if (ret != 0)
cmm_print(DEBUG_ERROR, "Error '%s' while trying to enable fast-forward\n", strerror(errno));
else
cmm_print(DEBUG_ERROR, "Error %d while trying to enable fast-forward\n", res_buf[0]);
}
else
{
globalConf.ff_enable = 1;
//zzz cmmSetTimeoutGlobal(globalConf.nfCtUpdateHandler, GLOBAL_SET_TIMEOUT_VALUE, FF_CT_TIMEOUT);
cmm_print(DEBUG_ERROR, "Fast-forward is enabled\n");
}
}
else
{
cmm_print(DEBUG_ERROR, "Fast-forward is already enabled\n");
}
}
else
{
if(globalConf.ff_enable)
{
cmd->enable = 0;
// Send message to forward engine
cmm_print(DEBUG_COMMAND, "Send CMD_IPV4_FF_CONTROL cmd len=%d\n",sizeof(fpp_ff_ctrl_cmd_t));
ret = fci_cmd(fci_handler, FPP_CMD_IPV4_FF_CONTROL, (unsigned short *) cmd, sizeof(fpp_ff_ctrl_cmd_t), res_buf, res_len);
if (ret !=0 || res_buf[0] != FPP_ERR_OK)
{
if (ret != 0)
cmm_print(DEBUG_ERROR, "Error '%s' while trying to enable fast-forward\n", strerror(errno));
else
cmm_print(DEBUG_ERROR, "Error %d while trying to enable fast-forward\n", res_buf[0]);
}
else
{
globalConf.ff_enable = 0;
//zzz cmmSetTimeoutGlobal(globalConf.nfCtUpdateHandler, GLOBAL_SET_TIMEOUT_LINUX, 0);
cmm_print(DEBUG_ERROR, "Fast-forward is disabled\n");
}
}
else
{
cmm_print(DEBUG_ERROR, "Fast-forward is already disabled\n");
}
}
return ret;
}
/*****************************************************************
* cmmFeCatch
*
*
******************************************************************/
int cmmFeCatch(unsigned short fcode, unsigned short len, unsigned short *payload)
{
switch (fcode)
{
case FPP_CMD_IPV4_CONNTRACK_CHANGE:
cmmFeCtChange4(&globalConf.ct, (fpp_ct_cmd_t*)payload, len);
break;
case FPP_CMD_IPV6_CONNTRACK_CHANGE:
cmmFeCtChange6(&globalConf.ct, (fpp_ct6_cmd_t*)payload, len);
break;
case FPP_CMD_IPSEC_SA_NOTIFY:
cmm_print(DEBUG_COMMAND, "CMD_IPSEC_SA_NOTIFY\n");
cmmIPSectoKeyEngine(globalConf.ct.fci_key_handle, fcode, len, payload);
break;
#ifdef AUTO_BRIDGE
case FPP_CMD_RX_L2FLOW_ENTRY:
cmmFeL2FlowChange(&globalConf.ct, (fpp_l2_bridge_flow_entry_cmd_t*)payload, len);
break;
#endif
default:
cmm_print(DEBUG_ERROR, "%s: Unknow command(%x) received\n", __func__, fcode);
break;
}
return FCI_CB_CONTINUE;
}