x710 VF use dpdk rte_flow_valida() return Function not implemented - virtualization

OS:CentOS 7.3
DPDK:19.08
I use one X710 NIC, create 2 VFs in kernel driver i40e, and bind vfio-pci driver on VF 0 and Start a DPDK PMD application.
Then I try to create a Flow Rule use rte_flow, but it returns -38, Function not implemented when I called rte_flow_validate().
Does it means this VF doesn't support rte_flow API? or there are some configure or flags need to be set on VF?

DPDK RTE_FLOW are supported on both PF and VF for X710 (Fortville) NIC, with actions like
RTE_FLOW_ACTION_TYPE_QUEUE
RTE_FLOW_ACTION_TYPE_DROP
RTE_FLOW_ACTION_TYPE_PASSTHRU
RTE_FLOW_ACTION_TYPE_MARK
RTE_FLOW_ACTION_TYPE_RSS
The return value -38 for DPDK API is not Function not implemented, but actually I40E_ERR_OPCODE_MISMATCH. This means either Lookup parameters or match cases are improperly configured. Code Snippet that works on X710 VF, shared below
/* configure for 2 RX queues */
struct rte_flow_attr attr = { .ingress = 1 };
struct rte_flow_item pattern[10];
struct rte_flow_action actions[10];
struct rte_flow_item_eth eth;
struct rte_flow_item_eth eth_mask;
struct rte_flow_item_vlan vlan;
struct rte_flow_item_vlan vlan_mask;
struct rte_flow_item_ipv4 ipv4;
struct rte_flow_item_ipv4 ipv4_mask;
struct rte_flow *flow;
struct rte_flow_action_mark mark = { .id = 0xdeadbeef };
struct rte_flow_action_queue queue = { .index = 0x3 };
memset(&pattern, 0, sizeof(pattern));
memset(&actions, 0, sizeof(actions));
memset(&attr, 0, sizeof(attr));
attr.group = 0;
attr.priority = 0;
attr.ingress = 1;
attr.egress = 0;
memset(&eth_mask, 0, sizeof(struct rte_flow_item_eth));
pattern[0].type = RTE_FLOW_ITEM_TYPE_ETH;
pattern[0].spec = ð
pattern[0].last = NULL;
pattern[0].mask = NULL;
memset(&vlan_mask, 0, sizeof(struct rte_flow_item_vlan));
pattern[1].type = RTE_FLOW_ITEM_TYPE_VLAN;
pattern[1].spec = &vlan;
pattern[1].last = NULL;
pattern[1].mask = NULL;
/* set the dst ipv4 packet to the required value */
pattern[1].type = RTE_FLOW_ITEM_TYPE_IPV4;
pattern[1].spec = NULL;
pattern[1].last = NULL;
pattern[1].mask = NULL;
pattern[2].type = RTE_FLOW_ITEM_TYPE_UDP;
pattern[2].spec = NULL;
pattern[2].last = NULL;
pattern[2].mask = NULL;
/* end the pattern array */
pattern[3].type = RTE_FLOW_ITEM_TYPE_END;
/* create the drop action */
actions[0].type = RTE_FLOW_ACTION_TYPE_MARK;
actions[0].conf = &mark;
actions[1].type = RTE_FLOW_ACTION_TYPE_END;
note: request #myzhu in comments to share the actual code snippet to root cause the issue too.

Related

Xilinx Echo Server Data Variable

I want to have my Zedboard return a numeric value using the Xilinx lwIP example as a base but no matter what I do I can't figure out what stores the data received or transmitted.
I have found the void type payload but I don't know what to do with it.
Snapshot of one instance of payload and a list of lwIP files
Below is the closest function to my goal:
err_t recv_callback(void *arg, struct tcp_pcb *tpcb,
struct pbuf *p, err_t err){
/* do not read the packet if we are not in ESTABLISHED state */
if (!p) {
tcp_close(tpcb);
tcp_recv(tpcb, NULL);
return ERR_OK;
}
/* indicate that the packet has been received */
tcp_recved(tpcb, p->len);
/* echo back the payload */
/* in this case, we assume that the payload is < TCP_SND_BUF */
if (tcp_sndbuf(tpcb) > p->len) {
err = tcp_write(tpcb, p->payload, p->len, 1);
//I need to change p->paylod but IDK where it is given a value.
} else
xil_printf("no space in tcp_sndbuf\n\r");
/* free the received pbuf */
pbuf_free(p);
return ERR_OK;
}
Any guidance is appreciated.
Thanks,
Turtlemii
-I cheated and just made sure that the function has access to Global_tpcb from echo.c
-tcp_write() reads in an address and displays each char it seems.
void Print_Code()
{
/* Prepare for TRANSMISSION */
char header[] = "\rSwitch: 1 2 3 4 5 6 7 8\n\r"; //header text
char data_t[] = " \n\r\r"; //area for storing the
data
unsigned char mask = 10000000; //mask to decode switches
swc_value = XGpio_DiscreteRead(&SWCInst, 1); //Save switch values
/* Write switch values to the LEDs for visual. */
XGpio_DiscreteWrite(&LEDInst, LED_CHANNEL, swc_value);
for (int i =0; i<=7; i++) //load data_t with switch values (0/1)
{
data_t[8+2*i] = '0' + ((swc_value & mask)/mask); //convert one bit to 0/1
mask = mask >> 1;//move to next bit
}
int len_header = *(&header + 1) - header; //find the length of the
header string
int len_data = *(&data_t + 1) - data_t; //find the length of the data string
tcp_write(Global_tpcb, &header, len_header, 1); //print the header
tcp_write(Global_tpcb, &data_t, len_data, 1); //print the data
}

interrupt handler not registered

I work on dragonboard410c that has the kernel module wcn36xx which registers this way:
static const struct of_device_id wcn36xx_of_match[] = {
{ .compatible = "qcom,wcnss-wlan" },
{}
};
MODULE_DEVICE_TABLE(of, wcn36xx_of_match);
static struct platform_driver wcn36xx_driver = {
.probe = wcn36xx_probe,
.remove = wcn36xx_remove,
.driver = {
.name = "wcn36xx",
.of_match_table = wcn36xx_of_match,
},
};
module_platform_driver(wcn36xx_driver);
I want to write my own kernel module that also registers to the same device , I have the code:
static const struct of_device_id my_interrupt_of_match[] = {
{ .compatible = "qcom,wcnss-wlan" },
{}
};
MODULE_DEVICE_TABLE(of, lab2_interrupt_of_match);
static struct platform_driver my_driver = {
.driver= {
.name = "my_interrupt",
.of_match_table = my_interrupt_of_match,
},
.probe = my_probe,
.remove = my_remove,
};
In the init function I register my driver:
int err = platform_driver_register(&my_driver);
But my probe function isn't called.
my module is automatically loaded on boot and the init function is called.
I build my module in a directory external to the kernel code and I put lab2_interrupt.ko on the board in the same directory as wcn36xx.ko:
/lib/modules/4.4.23-linaro-lt-qcom/kernel/drivers/net/wireless/ath/wcn36xx/
I guess that's because the corresponding platform device is already registered with the original wcn36xx_driver platform driver.
You should either disable it in your kernel build, or if it is built as a module, you could unload it with modprobe -r wcn36xx before loading your lab2_interrupt driver, or you could even blacklist it completely to prevent it to be loaded in the first place by adding such a line to /etc/modprobe.d/blacklist
blacklist wcn36xx

WFP ALE_CONNECT_REDIRECT layer block filter doesn't work

I am doing some work with WFP and I have the problem with blocking filter on FWPM_LAYER_ALE_CONNECT_REDIRECT_V4 layer. It must block trafic from local ip, but it doesn't. If I change layer to FWPM_LAYER_ALE_AUTH_CONNECT_V4 filter works properly.
So I have several questions:
1) Can I block trafic from specified local ip on FWPM_LAYER_ALE_CONNECT_REDIRECT_V4 layer (code below doesn't work)?
2) Can we create conditions with local_ip(remote_ip) on ale_connect_redirect(or ale_bind_redirect) layers?
UINT32 test_wfp_filter(HANDLE engine_handle,
FWP_V4_ADDR_AND_MASK* source_ip,
UINT8 weight)
{
UINT32 status;
FWPM_FILTER filter = { 0 };
FWPM_FILTER_CONDITION filter_conditions[1] = { 0 };
filter_conditions[0].fieldKey = FWPM_CONDITION_IP_LOCAL_ADDRESS;
filter_conditions[0].matchType = FWP_MATCH_EQUAL;
filter_conditions[0].conditionValue.type = FWP_V4_ADDR_MASK;
filter_conditions[0].conditionValue.v4AddrMask = source_ip;
status = UuidCreate(&(filter.filterKey));
if (status != NO_ERROR)
{
return status;
}
filter.layerKey = FWPM_LAYER_ALE_CONNECT_REDIRECT_V4;
//With this layerKey filter doesn't work,
//but with FWPM_LAYER_ALE_AUTH_CONNECT_V4 filter works properly
filter.displayData.name = L"Blocking filter";
filter.displayData.description = L"Blocks all trafic from current comp";
filter.action.type = FWP_ACTION_BLOCK;
filter.subLayerKey = WFP_TEST_SUBLAYER;
filter.weight.type = FWP_UINT8;
filter.weight.uint8 = weight;
filter.filterCondition = filter_conditions;
filter.numFilterConditions = 1;
status = FwpmFilterAdd(engine_handle, &filter, 0, 0);
return 0;
}
Thank you!
It's not 100% obvious what you are trying to achieve but:
No, the ALE_CONNECT_REDIRECT and ALE_BIND_REDIRECT layers are for modifying source/destination details associated with a flow (prior to establishment), not blocking the flow. An example usage would be writing a local proxy; you might install an ALE_CONNECT_REDIRECT callout which modifies the destination details for an attempted connection such that the connection is actually made to your own application rather than where it was originally intended.
You can definitely use source and destination IP address conditions with ALE_CONNECT_REDIRECT and ALE_BIND_REDIRECT, just remember that these layers are for redirecting not blocking.

NVIC_SystemReset () not working for STM32F4

I am working on STM32F4 board. My IDE is IAR Embedded Work bench. I am trying to do a software reset from code. For that i used API ' NVIC_SystemReset(); ' defined in
core_cm4.h header. But the system reset is not happening.
I tried the same thing in STM32F3, same IDE . I used the function NVIC_SystemReset(); from core_sc300.h header. Using that software reset is happening. I found the definition of functions in both file are same and both controllers are Cortex M4 only.What is the problem with STM32F4 board.? Can any one help me in solving this or can any one suggest an alternative way for system reset in STM32F4.
Please help.
Thanks in advance
In the HAL You can use
HAL_NVIC_SystemReset();
You can use a watch-dog instead:
Call wdg_activate(n) in order to initiate system-reset within n milliseconds
Call wdg_reactivate() in order to reload the counter back to n milliseconds
void wdg_activate(unsigned short num_of_ms)
{
uint8_t prescale_reg;
uint8_t prescale_val;
if (num_of_ms < 1)
{
num_of_ms = 1;
prescale_reg = IWDG_Prescaler_32;
prescale_val = 1;
}
else if (num_of_ms <= 4096)
{
prescale_reg = IWDG_Prescaler_32;
prescale_val = 1;
}
else if (num_of_ms <= 8192)
{
prescale_reg = IWDG_Prescaler_64;
prescale_val = 2;
}
else if (num_of_ms <= 16384)
{
prescale_reg = IWDG_Prescaler_128;
prescale_val = 4;
}
else if (num_of_ms <= 32768)
{
prescale_reg = IWDG_Prescaler_256;
prescale_val = 8;
}
else
{
num_of_ms = 32768;
prescale_reg = IWDG_Prescaler_256;
prescale_val = 8;
}
IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable);
while (IWDG_GetFlagStatus(IWDG_FLAG_PVU));
IWDG_SetPrescaler(prescale_reg);
while (IWDG_GetFlagStatus(IWDG_FLAG_RVU));
IWDG_SetReload(num_of_ms/prescale_val-1);
IWDG_Enable();
}
void wdg_reactivate()
{
IWDG_ReloadCounter();
}
There have been several iterations of NVIC_SystemReset(). Please post the code for the version you are using. The current [working STM32F4] version that I am using is as follows:
/** \brief System Reset
The function initiates a system reset request to reset the MCU.
*/
__STATIC_INLINE void NVIC_SystemReset(void)
{
__DSB(); /* Ensure all outstanding memory accesses included
buffered write are completed before reset */
SCB->AIRCR = ((0x5FA << SCB_AIRCR_VECTKEY_Pos) |
(SCB->AIRCR & SCB_AIRCR_PRIGROUP_Msk) |
SCB_AIRCR_SYSRESETREQ_Msk); /* Keep priority group unchanged */
__DSB(); /* Ensure completion of memory access */
while(1); /* wait until reset */
}

Implementing an OPC DA client from scratch

I would like to implement my own OPC DA client (versions 2.02, 2.05a, 3.00) from scratch but without using any third-party. Also I would like to make use of OPCEnum.exe service to get a list of installed OPC servers. Is there any kind of document that explains detailed and step by step the process to implement an OPC client?
I have a c# implementation but actually it's hard to fit it in here. I'll try to summarize the steps required.
Mostly you need to have OpcRcw.Comn.dll and OpcRcw.Da.dll from the OPC Core Components Redistributable package downloable for free from Opcfoundation.org. Once installed, the files are located in C:\Windows\assembly\GAC_MSIL. Create a reference in your project.
About coding, this is what you should do (there are three objects you want to implement, Server, Group and Item):
Let's start with server:
Type typeofOPCserver = Type.GetTypeFromProgID(serverName, computerName, true);
m_opcServer = (IOPCServer)Activator.CreateInstance(typeofOPCserver);
m_opcCommon = (IOPCCommon)m_opcServer;
IConnectionPointContainer icpc = (IConnectionPointContainer)m_opcServer;
Guid sinkGUID = typeof(IOPCShutdown).GUID;
icpc.FindConnectionPoint(ref sinkGUID, out m_OPCCP);
m_OPCCP.Advise(this, out m_cookie_CP);
I've striped a LOT of checking to fit it in here, take it as a sample...
Then you need a method on server to add groups:
// Parameter as following:
// [in] active, so do OnDataChange callback
// [in] Request this Update Rate from Server
// [in] Client Handle, not necessary in this sample
// [in] No time interval to system UTC time
// [in] No Deadband, so all data changes are reported
// [in] Server uses english language to for text values
// [out] Server handle to identify this group in later calls
// [out] The answer from Server to the requested Update Rate
// [in] requested interface type of the group object
// [out] pointer to the requested interface
m_opcServer.AddGroup(m_groupName, Convert.ToInt32(m_isActive), m_reqUpdateRate, m_clientHandle, pTimeBias, pDeadband, m_LocaleID, out m_serverHandle, out m_revUpdateRate, ref iid, out objGroup);
// Get our reference from the created group
m_OPCGroupStateMgt = (IOPCGroupStateMgt)objGroup;
Finally you need to create items:
m_OPCItem = (IOPCItemMgt)m_OPCGroupStateMgt;
m_OPCItem.AddItems(itemList.Length, GetAllItemDefs(itemList), out ppResults, out ppErrors);
Where itemlist is an array of OPCITEMDEF[]. I build the above using GetAllItemDefs from a structure of mine.
private static OPCITEMDEF[] GetAllItemDefs(params OpcItem[] opcItemList)
{
OPCITEMDEF[] opcItemDefs = new OPCITEMDEF[opcItemList.Length];
for (int i = 0; i < opcItemList.Length; i++)
{
OpcItem opcItem = opcItemList[i];
opcItemDefs[i].szAccessPath = "";
opcItemDefs[i].bActive = Convert.ToInt32(opcItem.IsActive);
opcItemDefs[i].vtRequestedDataType = Convert.ToInt16(opcItem.ItemType, CultureInfo.InvariantCulture);
opcItemDefs[i].dwBlobSize = 0;
opcItemDefs[i].pBlob = IntPtr.Zero;
opcItemDefs[i].hClient = opcItem.ClientHandle;
opcItemDefs[i].szItemID = opcItem.Id;
}
return opcItemDefs;
}
Finally, about enumerating Servers, I use this two functions:
/// <summary>
/// Enumerates hosts that may be accessed for server discovery.
/// </summary>
[SecurityPermission(SecurityAction.LinkDemand, UnmanagedCode = true)]
public string[] EnumerateHosts()
{
IntPtr pInfo;
int entriesRead = 0;
int totalEntries = 0;
int result = NetServerEnum(
IntPtr.Zero,
LEVEL_SERVER_INFO_100,
out pInfo,
MAX_PREFERRED_LENGTH,
out entriesRead,
out totalEntries,
SV_TYPE_WORKSTATION | SV_TYPE_SERVER,
IntPtr.Zero,
IntPtr.Zero);
if (result != 0)
throw new ApplicationException("NetApi Error = " + String.Format("0x{0,0:X}", result));
string[] computers = new string[entriesRead];
IntPtr pos = pInfo;
for (int ii = 0; ii < entriesRead; ii++)
{
SERVER_INFO_100 info = (SERVER_INFO_100)Marshal.PtrToStructure(pos, typeof(SERVER_INFO_100));
computers[ii] = info.sv100_name;
pos = (IntPtr)(pos.ToInt32() + Marshal.SizeOf(typeof(SERVER_INFO_100)));
}
NetApiBufferFree(pInfo);
return computers;
}
/// <summary>
/// Returns a list of servers that support the specified specification on the specified host.
/// </summary>
[SecurityPermission(SecurityAction.LinkDemand, UnmanagedCode = true)]
public string[] GetAvailableServers(Specification specification)
{
lock (this)
{
// connect to the server.
ArrayList servers = new ArrayList();
MULTI_QI[] results = new MULTI_QI[1];
GCHandle hIID = GCHandle.Alloc(IID_IUnknown, GCHandleType.Pinned);
results[0].iid = hIID.AddrOfPinnedObject();
results[0].pItf = null;
results[0].hr = 0;
try
{
// create an instance.
Guid srvid = CLSID;
CoCreateInstanceEx(srvid, null, CLSCTX.CLSCTX_LOCAL_SERVER, IntPtr.Zero, 1, results);
m_server = (IOPCServerList2)results[0].pItf;
// convert the interface version to a guid.
Guid catid = new Guid(specification.ID);
// get list of servers in the specified specification.
IOPCEnumGUID enumerator = null;
m_server.EnumClassesOfCategories(1, new Guid[] { catid }, 0, null, out enumerator);
// read clsids.
Guid[] clsids = ReadClasses(enumerator);
// release enumerator
if (enumerator != null && enumerator.GetType().IsCOMObject)
Marshal.ReleaseComObject(enumerator);
// fetch class descriptions.
foreach (Guid clsid in clsids)
{
try
{
string url = CreateUrl(specification, clsid);
servers.Add(url);
}
catch (Exception) { }
}
}
catch
{
}
finally
{
if (hIID.IsAllocated) hIID.Free();
if (m_server != null && m_server.GetType().IsCOMObject)
Marshal.ReleaseComObject(m_server);
}
return (string[])servers.ToArray(typeof(string));
}
}
I know I've striped a lot but maybe it can still help you ;)
Please mark the answer as correct if you think I've been clear ;)
Kind Regards,
D.