Fix issue in l3 mode when no arp reply was received 23/65423/3
authorXavier Simonart <xavier.simonart@intel.com>
Tue, 27 Nov 2018 14:03:21 +0000 (15:03 +0100)
committerXavier Simonart <xavier.simonart@intel.com>
Thu, 13 Dec 2018 15:21:20 +0000 (16:21 +0100)
When no arp reply was received in l3 mode, the requesting core
continuously sends ARP requests every seconds (which is correct).
But master core was keeping a list of all requests, while all
those requests are the same, resulting in potential table overflow.

Change-Id: I13aa1ec4ea88404a690a25678fb6ec72df19a9b9
Signed-off-by: Xavier Simonart <xavier.simonart@intel.com>
VNFs/DPPD-PROX/handle_master.c

index 853df42..2252741 100644 (file)
@@ -118,7 +118,7 @@ void register_ip_to_ctrl_plane(struct task_base *tbase, uint32_t ip, uint8_t por
        plogx_dbg("\tregistering IP %d.%d.%d.%d with port %d core %d and task %d\n", IP4(ip), port_id, core_id, task_id);
 
        if (port_id >= PROX_MAX_PORTS) {
-               plog_err("Unable to register ip %x, port %d\n", ip, port_id);
+               plog_err("Unable to register ip %d.%d.%d.%d, port %d\n", IP4(ip), port_id);
                return;
        }
 
@@ -138,7 +138,7 @@ void register_ip_to_ctrl_plane(struct task_base *tbase, uint32_t ip, uint8_t por
        key.port = port_id;
        int ret = rte_hash_add_key(task->internal_ip_hash, (const void *)&key);
        if (unlikely(ret < 0)) {
-               plog_err("Unable to register ip %x\n", ip);
+               plog_err("Unable to register ip %d.%d.%d.%d\n", IP4(ip));
                return;
        }
        memcpy(&task->internal_ip_table[ret].mac, &prox_port_cfg[port_id].eth_addr, 6);
@@ -216,7 +216,7 @@ static inline void handle_unknown_ip(struct task_base *tbase, struct rte_mbuf *m
        struct ether_hdr_arp *hdr_arp = rte_pktmbuf_mtod(mbuf, struct ether_hdr_arp *);
        uint8_t port = get_port(mbuf);
        uint32_t ip_dst = get_ip(mbuf);
-       int ret1, ret2;
+       int ret1, ret2, i;
 
        plogx_dbg("\tMaster handling unknown ip %d.%d.%d.%d for port %d\n", IP4(ip_dst), port);
        if (unlikely(port >= PROX_MAX_PORTS)) {
@@ -236,13 +236,32 @@ static inline void handle_unknown_ip(struct task_base *tbase, struct rte_mbuf *m
        ret2 = rte_hash_add_key(task->external_ip_hash, (const void *)&ip_dst);
        if (unlikely(ret2 < 0)) {
                // entry not found for this IP: delete the reply
-               plogx_dbg("Unable to add IP %x in external_ip_hash\n", rte_be_to_cpu_32(hdr_arp->arp.data.tpa));
+               plogx_dbg("Unable to add IP %d.%d.%d.%d in external_ip_hash\n", IP4(ip_dst));
                tx_drop(mbuf);
                return;
        }
-       task->external_ip_table[ret2].rings[task->external_ip_table[ret2].nb_requests] = ring;
-       task->external_ip_table[ret2].nb_requests++;
-       memcpy(&task->external_ip_table[ret2].mac, &task->internal_port_table[port].mac, 6);
+
+       // If multiple tasks requesting the same info, we will need to send a reply to all of them
+       // However if one task sends multiple requests to the same IP (e.g. because it is not answering)
+       // then we should not send multiple replies to the same task
+       if (task->external_ip_table[ret2].nb_requests >= PROX_MAX_ARP_REQUESTS) {
+               // This can only happen if really many tasks requests the same IP
+               plogx_dbg("Unable to add request for IP %d.%d.%d.%d in external_ip_table\n", IP4(ip_dst));
+               tx_drop(mbuf);
+               return;
+       }
+       for (i = 0; i < task->external_ip_table[ret2].nb_requests; i++) {
+               if (task->external_ip_table[ret2].rings[i] == ring)
+                       break;
+       }
+       if (i >= task->external_ip_table[ret2].nb_requests) {
+               // If this is a new request i.e. a new task requesting a new IP
+               task->external_ip_table[ret2].rings[task->external_ip_table[ret2].nb_requests] = ring;
+               task->external_ip_table[ret2].nb_requests++;
+               // Only needed for first request - but avoid test and copy the same 6 bytes
+               // In most cases we will only have one request per IP.
+               memcpy(&task->external_ip_table[ret2].mac, &task->internal_port_table[port].mac, 6);
+       }
 
        // We send an ARP request even if one was just sent (and not yet answered) by another task
        mbuf->ol_flags &= ~(PKT_TX_IP_CKSUM|PKT_TX_UDP_CKSUM);