Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net

Conflicts:
	net/ipv6/xfrm6_output.c
	net/openvswitch/flow_netlink.c
	net/openvswitch/vport-gre.c
	net/openvswitch/vport-vxlan.c
	net/openvswitch/vport.c
	net/openvswitch/vport.h

The openvswitch conflicts were overlapping changes.  One was
the egress tunnel info fix in 'net' and the other was the
vport ->send() op simplification in 'net-next'.

The xfrm6_output.c conflicts was also a simplification
overlapping a bug fix.

Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
David S. Miller 2015-10-24 06:54:12 -07:00
commit ba3e2084f2
69 changed files with 772 additions and 405 deletions

View File

@ -46,6 +46,7 @@ Required properties:
Optional properties: Optional properties:
- dual_emac_res_vlan : Specifies VID to be used to segregate the ports - dual_emac_res_vlan : Specifies VID to be used to segregate the ports
- mac-address : See ethernet.txt file in the same directory - mac-address : See ethernet.txt file in the same directory
- phy-handle : See ethernet.txt file in the same directory
Note: "ti,hwmods" field is used to fetch the base address and irq Note: "ti,hwmods" field is used to fetch the base address and irq
resources from TI, omap hwmod data base during device registration. resources from TI, omap hwmod data base during device registration.

View File

@ -0,0 +1,24 @@
SMSC LAN87xx Ethernet PHY
Some boards require special tuning values. Configure them
through an Ethernet OF device node.
Optional properties:
- smsc,disable-energy-detect:
If set, do not enable energy detect mode for the SMSC phy.
default: enable energy detect mode
Examples:
smsc phy with disabled energy detect mode on an am335x based board.
&davinci_mdio {
pinctrl-names = "default", "sleep";
pinctrl-0 = <&davinci_mdio_default>;
pinctrl-1 = <&davinci_mdio_sleep>;
status = "okay";
ethernetphy0: ethernet-phy@0 {
reg = <0>;
smsc,disable-energy-detect;
};
};

View File

@ -1247,7 +1247,7 @@ static void
l2_pull_iqueue(struct FsmInst *fi, int event, void *arg) l2_pull_iqueue(struct FsmInst *fi, int event, void *arg)
{ {
struct PStack *st = fi->userdata; struct PStack *st = fi->userdata;
struct sk_buff *skb; struct sk_buff *skb, *nskb;
struct Layer2 *l2 = &st->l2; struct Layer2 *l2 = &st->l2;
u_char header[MAX_HEADER_LEN]; u_char header[MAX_HEADER_LEN];
int i, hdr_space_needed; int i, hdr_space_needed;
@ -1262,14 +1262,10 @@ l2_pull_iqueue(struct FsmInst *fi, int event, void *arg)
return; return;
hdr_space_needed = l2headersize(l2, 0); hdr_space_needed = l2headersize(l2, 0);
if (hdr_space_needed > skb_headroom(skb)) { nskb = skb_realloc_headroom(skb, hdr_space_needed);
struct sk_buff *orig_skb = skb; if (!nskb) {
skb_queue_head(&l2->i_queue, skb);
skb = skb_realloc_headroom(skb, hdr_space_needed); return;
if (!skb) {
dev_kfree_skb(orig_skb);
return;
}
} }
spin_lock_irqsave(&l2->lock, flags); spin_lock_irqsave(&l2->lock, flags);
if (test_bit(FLG_MOD128, &l2->flag)) if (test_bit(FLG_MOD128, &l2->flag))
@ -1282,7 +1278,7 @@ l2_pull_iqueue(struct FsmInst *fi, int event, void *arg)
p1); p1);
dev_kfree_skb(l2->windowar[p1]); dev_kfree_skb(l2->windowar[p1]);
} }
l2->windowar[p1] = skb_clone(skb, GFP_ATOMIC); l2->windowar[p1] = skb;
i = sethdraddr(&st->l2, header, CMD); i = sethdraddr(&st->l2, header, CMD);
@ -1295,8 +1291,8 @@ l2_pull_iqueue(struct FsmInst *fi, int event, void *arg)
l2->vs = (l2->vs + 1) % 8; l2->vs = (l2->vs + 1) % 8;
} }
spin_unlock_irqrestore(&l2->lock, flags); spin_unlock_irqrestore(&l2->lock, flags);
memcpy(skb_push(skb, i), header, i); memcpy(skb_push(nskb, i), header, i);
st->l2.l2l1(st, PH_PULL | INDICATION, skb); st->l2.l2l1(st, PH_PULL | INDICATION, nskb);
test_and_clear_bit(FLG_ACK_PEND, &st->l2.flag); test_and_clear_bit(FLG_ACK_PEND, &st->l2.flag);
if (!test_and_set_bit(FLG_T200_RUN, &st->l2.flag)) { if (!test_and_set_bit(FLG_T200_RUN, &st->l2.flag)) {
FsmDelTimer(&st->l2.t203, 13); FsmDelTimer(&st->l2.t203, 13);

View File

@ -1476,7 +1476,7 @@ static void
l2_pull_iqueue(struct FsmInst *fi, int event, void *arg) l2_pull_iqueue(struct FsmInst *fi, int event, void *arg)
{ {
struct layer2 *l2 = fi->userdata; struct layer2 *l2 = fi->userdata;
struct sk_buff *skb, *nskb, *oskb; struct sk_buff *skb, *nskb;
u_char header[MAX_L2HEADER_LEN]; u_char header[MAX_L2HEADER_LEN];
u_int i, p1; u_int i, p1;
@ -1486,11 +1486,26 @@ l2_pull_iqueue(struct FsmInst *fi, int event, void *arg)
skb = skb_dequeue(&l2->i_queue); skb = skb_dequeue(&l2->i_queue);
if (!skb) if (!skb)
return; return;
i = sethdraddr(l2, header, CMD);
if (test_bit(FLG_MOD128, &l2->flag)) if (test_bit(FLG_MOD128, &l2->flag)) {
header[i++] = l2->vs << 1;
header[i++] = l2->vr << 1;
} else
header[i++] = (l2->vr << 5) | (l2->vs << 1);
nskb = skb_realloc_headroom(skb, i);
if (!nskb) {
printk(KERN_WARNING "%s: no headroom(%d) copy for IFrame\n",
mISDNDevName4ch(&l2->ch), i);
skb_queue_head(&l2->i_queue, skb);
return;
}
if (test_bit(FLG_MOD128, &l2->flag)) {
p1 = (l2->vs - l2->va) % 128; p1 = (l2->vs - l2->va) % 128;
else l2->vs = (l2->vs + 1) % 128;
} else {
p1 = (l2->vs - l2->va) % 8; p1 = (l2->vs - l2->va) % 8;
l2->vs = (l2->vs + 1) % 8;
}
p1 = (p1 + l2->sow) % l2->window; p1 = (p1 + l2->sow) % l2->window;
if (l2->windowar[p1]) { if (l2->windowar[p1]) {
printk(KERN_WARNING "%s: l2 try overwrite ack queue entry %d\n", printk(KERN_WARNING "%s: l2 try overwrite ack queue entry %d\n",
@ -1498,36 +1513,7 @@ l2_pull_iqueue(struct FsmInst *fi, int event, void *arg)
dev_kfree_skb(l2->windowar[p1]); dev_kfree_skb(l2->windowar[p1]);
} }
l2->windowar[p1] = skb; l2->windowar[p1] = skb;
i = sethdraddr(l2, header, CMD); memcpy(skb_push(nskb, i), header, i);
if (test_bit(FLG_MOD128, &l2->flag)) {
header[i++] = l2->vs << 1;
header[i++] = l2->vr << 1;
l2->vs = (l2->vs + 1) % 128;
} else {
header[i++] = (l2->vr << 5) | (l2->vs << 1);
l2->vs = (l2->vs + 1) % 8;
}
nskb = skb_clone(skb, GFP_ATOMIC);
p1 = skb_headroom(nskb);
if (p1 >= i)
memcpy(skb_push(nskb, i), header, i);
else {
printk(KERN_WARNING
"%s: L2 pull_iqueue skb header(%d/%d) too short\n",
mISDNDevName4ch(&l2->ch), i, p1);
oskb = nskb;
nskb = mI_alloc_skb(oskb->len + i, GFP_ATOMIC);
if (!nskb) {
dev_kfree_skb(oskb);
printk(KERN_WARNING "%s: no skb mem in %s\n",
mISDNDevName4ch(&l2->ch), __func__);
return;
}
memcpy(skb_put(nskb, i), header, i);
memcpy(skb_put(nskb, oskb->len), oskb->data, oskb->len);
dev_kfree_skb(oskb);
}
l2down(l2, PH_DATA_REQ, l2_newid(l2), nskb); l2down(l2, PH_DATA_REQ, l2_newid(l2), nskb);
test_and_clear_bit(FLG_ACK_PEND, &l2->flag); test_and_clear_bit(FLG_ACK_PEND, &l2->flag);
if (!test_and_set_bit(FLG_T200_RUN, &l2->flag)) { if (!test_and_set_bit(FLG_T200_RUN, &l2->flag)) {

View File

@ -847,21 +847,25 @@ static int emac_probe(struct platform_device *pdev)
if (ndev->irq == -ENXIO) { if (ndev->irq == -ENXIO) {
netdev_err(ndev, "No irq resource\n"); netdev_err(ndev, "No irq resource\n");
ret = ndev->irq; ret = ndev->irq;
goto out; goto out_iounmap;
} }
db->clk = devm_clk_get(&pdev->dev, NULL); db->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(db->clk)) { if (IS_ERR(db->clk)) {
ret = PTR_ERR(db->clk); ret = PTR_ERR(db->clk);
goto out; goto out_iounmap;
} }
clk_prepare_enable(db->clk); ret = clk_prepare_enable(db->clk);
if (ret) {
dev_err(&pdev->dev, "Error couldn't enable clock (%d)\n", ret);
goto out_iounmap;
}
ret = sunxi_sram_claim(&pdev->dev); ret = sunxi_sram_claim(&pdev->dev);
if (ret) { if (ret) {
dev_err(&pdev->dev, "Error couldn't map SRAM to device\n"); dev_err(&pdev->dev, "Error couldn't map SRAM to device\n");
goto out; goto out_clk_disable_unprepare;
} }
db->phy_node = of_parse_phandle(np, "phy", 0); db->phy_node = of_parse_phandle(np, "phy", 0);
@ -910,6 +914,10 @@ static int emac_probe(struct platform_device *pdev)
out_release_sram: out_release_sram:
sunxi_sram_release(&pdev->dev); sunxi_sram_release(&pdev->dev);
out_clk_disable_unprepare:
clk_disable_unprepare(db->clk);
out_iounmap:
iounmap(db->membase);
out: out:
dev_err(db->dev, "not found (%d).\n", ret); dev_err(db->dev, "not found (%d).\n", ret);
@ -921,8 +929,12 @@ out:
static int emac_remove(struct platform_device *pdev) static int emac_remove(struct platform_device *pdev)
{ {
struct net_device *ndev = platform_get_drvdata(pdev); struct net_device *ndev = platform_get_drvdata(pdev);
struct emac_board_info *db = netdev_priv(ndev);
unregister_netdev(ndev); unregister_netdev(ndev);
sunxi_sram_release(&pdev->dev);
clk_disable_unprepare(db->clk);
iounmap(db->membase);
free_netdev(ndev); free_netdev(ndev);
dev_dbg(&pdev->dev, "released and freed device\n"); dev_dbg(&pdev->dev, "released and freed device\n");

View File

@ -1595,7 +1595,7 @@ static void xgbe_dev_xmit(struct xgbe_channel *channel)
packet->rdesc_count, 1); packet->rdesc_count, 1);
/* Make sure ownership is written to the descriptor */ /* Make sure ownership is written to the descriptor */
dma_wmb(); wmb();
ring->cur = cur_index + 1; ring->cur = cur_index + 1;
if (!packet->skb->xmit_more || if (!packet->skb->xmit_more ||

View File

@ -1811,6 +1811,7 @@ static int xgbe_tx_poll(struct xgbe_channel *channel)
struct netdev_queue *txq; struct netdev_queue *txq;
int processed = 0; int processed = 0;
unsigned int tx_packets = 0, tx_bytes = 0; unsigned int tx_packets = 0, tx_bytes = 0;
unsigned int cur;
DBGPR("-->xgbe_tx_poll\n"); DBGPR("-->xgbe_tx_poll\n");
@ -1818,10 +1819,11 @@ static int xgbe_tx_poll(struct xgbe_channel *channel)
if (!ring) if (!ring)
return 0; return 0;
cur = ring->cur;
txq = netdev_get_tx_queue(netdev, channel->queue_index); txq = netdev_get_tx_queue(netdev, channel->queue_index);
while ((processed < XGBE_TX_DESC_MAX_PROC) && while ((processed < XGBE_TX_DESC_MAX_PROC) &&
(ring->dirty != ring->cur)) { (ring->dirty != cur)) {
rdata = XGBE_GET_DESC_DATA(ring, ring->dirty); rdata = XGBE_GET_DESC_DATA(ring, ring->dirty);
rdesc = rdata->rdesc; rdesc = rdata->rdesc;

View File

@ -2048,7 +2048,7 @@ static void swphy_poll_timer(unsigned long data)
for (i = 0; i < priv->num_ports; i++) { for (i = 0; i < priv->num_ports; i++) {
struct bcm63xx_enetsw_port *port; struct bcm63xx_enetsw_port *port;
int val, j, up, advertise, lpa, lpa2, speed, duplex, media; int val, j, up, advertise, lpa, speed, duplex, media;
int external_phy = bcm_enet_port_is_rgmii(i); int external_phy = bcm_enet_port_is_rgmii(i);
u8 override; u8 override;
@ -2091,22 +2091,27 @@ static void swphy_poll_timer(unsigned long data)
lpa = bcmenet_sw_mdio_read(priv, external_phy, port->phy_id, lpa = bcmenet_sw_mdio_read(priv, external_phy, port->phy_id,
MII_LPA); MII_LPA);
lpa2 = bcmenet_sw_mdio_read(priv, external_phy, port->phy_id,
MII_STAT1000);
/* figure out media and duplex from advertise and LPA values */ /* figure out media and duplex from advertise and LPA values */
media = mii_nway_result(lpa & advertise); media = mii_nway_result(lpa & advertise);
duplex = (media & ADVERTISE_FULL) ? 1 : 0; duplex = (media & ADVERTISE_FULL) ? 1 : 0;
if (lpa2 & LPA_1000FULL)
duplex = 1;
if (lpa2 & (LPA_1000FULL | LPA_1000HALF)) if (media & (ADVERTISE_100FULL | ADVERTISE_100HALF))
speed = 1000; speed = 100;
else { else
if (media & (ADVERTISE_100FULL | ADVERTISE_100HALF)) speed = 10;
speed = 100;
else if (val & BMSR_ESTATEN) {
speed = 10; advertise = bcmenet_sw_mdio_read(priv, external_phy,
port->phy_id, MII_CTRL1000);
lpa = bcmenet_sw_mdio_read(priv, external_phy,
port->phy_id, MII_STAT1000);
if (advertise & (ADVERTISE_1000FULL | ADVERTISE_1000HALF)
&& lpa & (LPA_1000FULL | LPA_1000HALF)) {
speed = 1000;
duplex = (lpa & LPA_1000FULL);
}
} }
dev_info(&priv->pdev->dev, dev_info(&priv->pdev->dev,

View File

@ -3,7 +3,7 @@
# #
config NET_VENDOR_CAVIUM config NET_VENDOR_CAVIUM
tristate "Cavium ethernet drivers" bool "Cavium ethernet drivers"
depends on PCI depends on PCI
default y default y
---help--- ---help---

View File

@ -1406,6 +1406,12 @@ static void i40e_get_ethtool_stats(struct net_device *netdev,
data[i++] = (i40e_gstrings_veb_stats[j].sizeof_stat == data[i++] = (i40e_gstrings_veb_stats[j].sizeof_stat ==
sizeof(u64)) ? *(u64 *)p : *(u32 *)p; sizeof(u64)) ? *(u64 *)p : *(u32 *)p;
} }
for (j = 0; j < I40E_MAX_TRAFFIC_CLASS; j++) {
data[i++] = veb->tc_stats.tc_tx_packets[j];
data[i++] = veb->tc_stats.tc_tx_bytes[j];
data[i++] = veb->tc_stats.tc_rx_packets[j];
data[i++] = veb->tc_stats.tc_rx_bytes[j];
}
} }
for (j = 0; j < I40E_GLOBAL_STATS_LEN; j++) { for (j = 0; j < I40E_GLOBAL_STATS_LEN; j++) {
p = (char *)pf + i40e_gstrings_stats[j].stat_offset; p = (char *)pf + i40e_gstrings_stats[j].stat_offset;

View File

@ -8154,6 +8154,7 @@ static int i40e_sw_init(struct i40e_pf *pf)
if (pf->hw.func_caps.vmdq) { if (pf->hw.func_caps.vmdq) {
pf->num_vmdq_vsis = I40E_DEFAULT_NUM_VMDQ_VSI; pf->num_vmdq_vsis = I40E_DEFAULT_NUM_VMDQ_VSI;
pf->flags |= I40E_FLAG_VMDQ_ENABLED; pf->flags |= I40E_FLAG_VMDQ_ENABLED;
pf->num_vmdq_qps = i40e_default_queues_per_vmdq(pf);
} }
#ifdef I40E_FCOE #ifdef I40E_FCOE

View File

@ -759,11 +759,23 @@ txq_put_data_tso(struct net_device *dev, struct tx_queue *txq,
desc->l4i_chk = 0; desc->l4i_chk = 0;
desc->byte_cnt = length; desc->byte_cnt = length;
desc->buf_ptr = dma_map_single(dev->dev.parent, data,
length, DMA_TO_DEVICE); if (length <= 8 && (uintptr_t)data & 0x7) {
if (unlikely(dma_mapping_error(dev->dev.parent, desc->buf_ptr))) { /* Copy unaligned small data fragment to TSO header data area */
WARN(1, "dma_map_single failed!\n"); memcpy(txq->tso_hdrs + txq->tx_curr_desc * TSO_HEADER_SIZE,
return -ENOMEM; data, length);
desc->buf_ptr = txq->tso_hdrs_dma
+ txq->tx_curr_desc * TSO_HEADER_SIZE;
} else {
/* Alignment is okay, map buffer and hand off to hardware */
txq->tx_desc_mapping[tx_index] = DESC_DMA_MAP_SINGLE;
desc->buf_ptr = dma_map_single(dev->dev.parent, data,
length, DMA_TO_DEVICE);
if (unlikely(dma_mapping_error(dev->dev.parent,
desc->buf_ptr))) {
WARN(1, "dma_map_single failed!\n");
return -ENOMEM;
}
} }
cmd_sts = BUFFER_OWNED_BY_DMA; cmd_sts = BUFFER_OWNED_BY_DMA;
@ -779,7 +791,8 @@ txq_put_data_tso(struct net_device *dev, struct tx_queue *txq,
} }
static inline void static inline void
txq_put_hdr_tso(struct sk_buff *skb, struct tx_queue *txq, int length) txq_put_hdr_tso(struct sk_buff *skb, struct tx_queue *txq, int length,
u32 *first_cmd_sts, bool first_desc)
{ {
struct mv643xx_eth_private *mp = txq_to_mp(txq); struct mv643xx_eth_private *mp = txq_to_mp(txq);
int hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb); int hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb);
@ -788,6 +801,7 @@ txq_put_hdr_tso(struct sk_buff *skb, struct tx_queue *txq, int length)
int ret; int ret;
u32 cmd_csum = 0; u32 cmd_csum = 0;
u16 l4i_chk = 0; u16 l4i_chk = 0;
u32 cmd_sts;
tx_index = txq->tx_curr_desc; tx_index = txq->tx_curr_desc;
desc = &txq->tx_desc_area[tx_index]; desc = &txq->tx_desc_area[tx_index];
@ -803,9 +817,17 @@ txq_put_hdr_tso(struct sk_buff *skb, struct tx_queue *txq, int length)
desc->byte_cnt = hdr_len; desc->byte_cnt = hdr_len;
desc->buf_ptr = txq->tso_hdrs_dma + desc->buf_ptr = txq->tso_hdrs_dma +
txq->tx_curr_desc * TSO_HEADER_SIZE; txq->tx_curr_desc * TSO_HEADER_SIZE;
desc->cmd_sts = cmd_csum | BUFFER_OWNED_BY_DMA | TX_FIRST_DESC | cmd_sts = cmd_csum | BUFFER_OWNED_BY_DMA | TX_FIRST_DESC |
GEN_CRC; GEN_CRC;
/* Defer updating the first command descriptor until all
* following descriptors have been written.
*/
if (first_desc)
*first_cmd_sts = cmd_sts;
else
desc->cmd_sts = cmd_sts;
txq->tx_curr_desc++; txq->tx_curr_desc++;
if (txq->tx_curr_desc == txq->tx_ring_size) if (txq->tx_curr_desc == txq->tx_ring_size)
txq->tx_curr_desc = 0; txq->tx_curr_desc = 0;
@ -819,6 +841,8 @@ static int txq_submit_tso(struct tx_queue *txq, struct sk_buff *skb,
int desc_count = 0; int desc_count = 0;
struct tso_t tso; struct tso_t tso;
int hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb); int hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb);
struct tx_desc *first_tx_desc;
u32 first_cmd_sts = 0;
/* Count needed descriptors */ /* Count needed descriptors */
if ((txq->tx_desc_count + tso_count_descs(skb)) >= txq->tx_ring_size) { if ((txq->tx_desc_count + tso_count_descs(skb)) >= txq->tx_ring_size) {
@ -826,11 +850,14 @@ static int txq_submit_tso(struct tx_queue *txq, struct sk_buff *skb,
return -EBUSY; return -EBUSY;
} }
first_tx_desc = &txq->tx_desc_area[txq->tx_curr_desc];
/* Initialize the TSO handler, and prepare the first payload */ /* Initialize the TSO handler, and prepare the first payload */
tso_start(skb, &tso); tso_start(skb, &tso);
total_len = skb->len - hdr_len; total_len = skb->len - hdr_len;
while (total_len > 0) { while (total_len > 0) {
bool first_desc = (desc_count == 0);
char *hdr; char *hdr;
data_left = min_t(int, skb_shinfo(skb)->gso_size, total_len); data_left = min_t(int, skb_shinfo(skb)->gso_size, total_len);
@ -840,7 +867,8 @@ static int txq_submit_tso(struct tx_queue *txq, struct sk_buff *skb,
/* prepare packet headers: MAC + IP + TCP */ /* prepare packet headers: MAC + IP + TCP */
hdr = txq->tso_hdrs + txq->tx_curr_desc * TSO_HEADER_SIZE; hdr = txq->tso_hdrs + txq->tx_curr_desc * TSO_HEADER_SIZE;
tso_build_hdr(skb, hdr, &tso, data_left, total_len == 0); tso_build_hdr(skb, hdr, &tso, data_left, total_len == 0);
txq_put_hdr_tso(skb, txq, data_left); txq_put_hdr_tso(skb, txq, data_left, &first_cmd_sts,
first_desc);
while (data_left > 0) { while (data_left > 0) {
int size; int size;
@ -860,6 +888,10 @@ static int txq_submit_tso(struct tx_queue *txq, struct sk_buff *skb,
__skb_queue_tail(&txq->tx_skb, skb); __skb_queue_tail(&txq->tx_skb, skb);
skb_tx_timestamp(skb); skb_tx_timestamp(skb);
/* ensure all other descriptors are written before first cmd_sts */
wmb();
first_tx_desc->cmd_sts = first_cmd_sts;
/* clear TX_END status */ /* clear TX_END status */
mp->work_tx_end &= ~(1 << txq->index); mp->work_tx_end &= ~(1 << txq->index);

View File

@ -31,6 +31,7 @@
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
#include <linux/gpio.h> #include <linux/gpio.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_mdio.h>
#include <linux/of_net.h> #include <linux/of_net.h>
#include <linux/of_device.h> #include <linux/of_device.h>
#include <linux/if_vlan.h> #include <linux/if_vlan.h>
@ -366,6 +367,7 @@ struct cpsw_priv {
spinlock_t lock; spinlock_t lock;
struct platform_device *pdev; struct platform_device *pdev;
struct net_device *ndev; struct net_device *ndev;
struct device_node *phy_node;
struct napi_struct napi_rx; struct napi_struct napi_rx;
struct napi_struct napi_tx; struct napi_struct napi_tx;
struct device *dev; struct device *dev;
@ -1146,7 +1148,11 @@ static void cpsw_slave_open(struct cpsw_slave *slave, struct cpsw_priv *priv)
cpsw_ale_add_mcast(priv->ale, priv->ndev->broadcast, cpsw_ale_add_mcast(priv->ale, priv->ndev->broadcast,
1 << slave_port, 0, 0, ALE_MCAST_FWD_2); 1 << slave_port, 0, 0, ALE_MCAST_FWD_2);
slave->phy = phy_connect(priv->ndev, slave->data->phy_id, if (priv->phy_node)
slave->phy = of_phy_connect(priv->ndev, priv->phy_node,
&cpsw_adjust_link, 0, slave->data->phy_if);
else
slave->phy = phy_connect(priv->ndev, slave->data->phy_id,
&cpsw_adjust_link, slave->data->phy_if); &cpsw_adjust_link, slave->data->phy_if);
if (IS_ERR(slave->phy)) { if (IS_ERR(slave->phy)) {
dev_err(priv->dev, "phy %s not found on slave %d\n", dev_err(priv->dev, "phy %s not found on slave %d\n",
@ -1934,11 +1940,12 @@ static void cpsw_slave_init(struct cpsw_slave *slave, struct cpsw_priv *priv,
slave->port_vlan = data->dual_emac_res_vlan; slave->port_vlan = data->dual_emac_res_vlan;
} }
static int cpsw_probe_dt(struct cpsw_platform_data *data, static int cpsw_probe_dt(struct cpsw_priv *priv,
struct platform_device *pdev) struct platform_device *pdev)
{ {
struct device_node *node = pdev->dev.of_node; struct device_node *node = pdev->dev.of_node;
struct device_node *slave_node; struct device_node *slave_node;
struct cpsw_platform_data *data = &priv->data;
int i = 0, ret; int i = 0, ret;
u32 prop; u32 prop;
@ -2029,6 +2036,7 @@ static int cpsw_probe_dt(struct cpsw_platform_data *data,
if (strcmp(slave_node->name, "slave")) if (strcmp(slave_node->name, "slave"))
continue; continue;
priv->phy_node = of_parse_phandle(slave_node, "phy-handle", 0);
parp = of_get_property(slave_node, "phy_id", &lenp); parp = of_get_property(slave_node, "phy_id", &lenp);
if ((parp == NULL) || (lenp != (sizeof(void *) * 2))) { if ((parp == NULL) || (lenp != (sizeof(void *) * 2))) {
dev_err(&pdev->dev, "Missing slave[%d] phy_id property\n", i); dev_err(&pdev->dev, "Missing slave[%d] phy_id property\n", i);
@ -2044,7 +2052,6 @@ static int cpsw_probe_dt(struct cpsw_platform_data *data,
} }
snprintf(slave_data->phy_id, sizeof(slave_data->phy_id), snprintf(slave_data->phy_id, sizeof(slave_data->phy_id),
PHY_ID_FMT, mdio->name, phyid); PHY_ID_FMT, mdio->name, phyid);
slave_data->phy_if = of_get_phy_mode(slave_node); slave_data->phy_if = of_get_phy_mode(slave_node);
if (slave_data->phy_if < 0) { if (slave_data->phy_if < 0) {
dev_err(&pdev->dev, "Missing or malformed slave[%d] phy-mode property\n", dev_err(&pdev->dev, "Missing or malformed slave[%d] phy-mode property\n",
@ -2245,7 +2252,7 @@ static int cpsw_probe(struct platform_device *pdev)
/* Select default pin state */ /* Select default pin state */
pinctrl_pm_select_default_state(&pdev->dev); pinctrl_pm_select_default_state(&pdev->dev);
if (cpsw_probe_dt(&priv->data, pdev)) { if (cpsw_probe_dt(priv, pdev)) {
dev_err(&pdev->dev, "cpsw: platform data missing\n"); dev_err(&pdev->dev, "cpsw: platform data missing\n");
ret = -ENODEV; ret = -ENODEV;
goto clean_runtime_disable_ret; goto clean_runtime_disable_ret;

View File

@ -594,14 +594,12 @@ static struct rtable *geneve_get_rt(struct sk_buff *skb,
rt = ip_route_output_key(geneve->net, fl4); rt = ip_route_output_key(geneve->net, fl4);
if (IS_ERR(rt)) { if (IS_ERR(rt)) {
netdev_dbg(dev, "no route to %pI4\n", &fl4->daddr); netdev_dbg(dev, "no route to %pI4\n", &fl4->daddr);
dev->stats.tx_carrier_errors++; return ERR_PTR(-ENETUNREACH);
return rt;
} }
if (rt->dst.dev == dev) { /* is this necessary? */ if (rt->dst.dev == dev) { /* is this necessary? */
netdev_dbg(dev, "circular route to %pI4\n", &fl4->daddr); netdev_dbg(dev, "circular route to %pI4\n", &fl4->daddr);
dev->stats.collisions++;
ip_rt_put(rt); ip_rt_put(rt);
return ERR_PTR(-EINVAL); return ERR_PTR(-ELOOP);
} }
return rt; return rt;
} }
@ -627,12 +625,12 @@ static netdev_tx_t geneve_xmit(struct sk_buff *skb, struct net_device *dev)
struct ip_tunnel_info *info = NULL; struct ip_tunnel_info *info = NULL;
struct rtable *rt = NULL; struct rtable *rt = NULL;
const struct iphdr *iip; /* interior IP header */ const struct iphdr *iip; /* interior IP header */
int err = -EINVAL;
struct flowi4 fl4; struct flowi4 fl4;
__u8 tos, ttl; __u8 tos, ttl;
__be16 sport; __be16 sport;
bool udp_csum; bool udp_csum;
__be16 df; __be16 df;
int err;
if (geneve->collect_md) { if (geneve->collect_md) {
info = skb_tunnel_info(skb); info = skb_tunnel_info(skb);
@ -647,7 +645,7 @@ static netdev_tx_t geneve_xmit(struct sk_buff *skb, struct net_device *dev)
rt = geneve_get_rt(skb, dev, &fl4, info); rt = geneve_get_rt(skb, dev, &fl4, info);
if (IS_ERR(rt)) { if (IS_ERR(rt)) {
netdev_dbg(dev, "no route to %pI4\n", &fl4.daddr); netdev_dbg(dev, "no route to %pI4\n", &fl4.daddr);
dev->stats.tx_carrier_errors++; err = PTR_ERR(rt);
goto tx_error; goto tx_error;
} }
@ -699,10 +697,37 @@ static netdev_tx_t geneve_xmit(struct sk_buff *skb, struct net_device *dev)
tx_error: tx_error:
dev_kfree_skb(skb); dev_kfree_skb(skb);
err: err:
dev->stats.tx_errors++; if (err == -ELOOP)
dev->stats.collisions++;
else if (err == -ENETUNREACH)
dev->stats.tx_carrier_errors++;
else
dev->stats.tx_errors++;
return NETDEV_TX_OK; return NETDEV_TX_OK;
} }
static int geneve_fill_metadata_dst(struct net_device *dev, struct sk_buff *skb)
{
struct ip_tunnel_info *info = skb_tunnel_info(skb);
struct geneve_dev *geneve = netdev_priv(dev);
struct rtable *rt;
struct flowi4 fl4;
if (ip_tunnel_info_af(info) != AF_INET)
return -EINVAL;
rt = geneve_get_rt(skb, dev, &fl4, info);
if (IS_ERR(rt))
return PTR_ERR(rt);
ip_rt_put(rt);
info->key.u.ipv4.src = fl4.saddr;
info->key.tp_src = udp_flow_src_port(geneve->net, skb,
1, USHRT_MAX, true);
info->key.tp_dst = geneve->dst_port;
return 0;
}
static const struct net_device_ops geneve_netdev_ops = { static const struct net_device_ops geneve_netdev_ops = {
.ndo_init = geneve_init, .ndo_init = geneve_init,
.ndo_uninit = geneve_uninit, .ndo_uninit = geneve_uninit,
@ -713,6 +738,7 @@ static const struct net_device_ops geneve_netdev_ops = {
.ndo_change_mtu = eth_change_mtu, .ndo_change_mtu = eth_change_mtu,
.ndo_validate_addr = eth_validate_addr, .ndo_validate_addr = eth_validate_addr,
.ndo_set_mac_address = eth_mac_addr, .ndo_set_mac_address = eth_mac_addr,
.ndo_fill_metadata_dst = geneve_fill_metadata_dst,
}; };
static void geneve_get_drvinfo(struct net_device *dev, static void geneve_get_drvinfo(struct net_device *dev,

View File

@ -137,7 +137,7 @@ static const struct proto_ops macvtap_socket_ops;
#define TUN_OFFLOADS (NETIF_F_HW_CSUM | NETIF_F_TSO_ECN | NETIF_F_TSO | \ #define TUN_OFFLOADS (NETIF_F_HW_CSUM | NETIF_F_TSO_ECN | NETIF_F_TSO | \
NETIF_F_TSO6 | NETIF_F_UFO) NETIF_F_TSO6 | NETIF_F_UFO)
#define RX_OFFLOADS (NETIF_F_GRO | NETIF_F_LRO) #define RX_OFFLOADS (NETIF_F_GRO | NETIF_F_LRO)
#define TAP_FEATURES (NETIF_F_GSO | NETIF_F_SG) #define TAP_FEATURES (NETIF_F_GSO | NETIF_F_SG | NETIF_F_FRAGLIST)
static struct macvlan_dev *macvtap_get_vlan_rcu(const struct net_device *dev) static struct macvlan_dev *macvtap_get_vlan_rcu(const struct net_device *dev)
{ {

View File

@ -141,6 +141,11 @@ config MICREL_PHY
---help--- ---help---
Supports the KSZ9021, VSC8201, KS8001 PHYs. Supports the KSZ9021, VSC8201, KS8001 PHYs.
config DP83848_PHY
tristate "Driver for Texas Instruments DP83848 PHY"
---help---
Supports the DP83848 PHY.
config DP83867_PHY config DP83867_PHY
tristate "Drivers for Texas Instruments DP83867 Gigabit PHY" tristate "Drivers for Texas Instruments DP83867 Gigabit PHY"
---help--- ---help---

View File

@ -26,6 +26,7 @@ obj-$(CONFIG_MDIO_BITBANG) += mdio-bitbang.o
obj-$(CONFIG_MDIO_GPIO) += mdio-gpio.o obj-$(CONFIG_MDIO_GPIO) += mdio-gpio.o
obj-$(CONFIG_NATIONAL_PHY) += national.o obj-$(CONFIG_NATIONAL_PHY) += national.o
obj-$(CONFIG_DP83640_PHY) += dp83640.o obj-$(CONFIG_DP83640_PHY) += dp83640.o
obj-$(CONFIG_DP83848_PHY) += dp83848.o
obj-$(CONFIG_DP83867_PHY) += dp83867.o obj-$(CONFIG_DP83867_PHY) += dp83867.o
obj-$(CONFIG_STE10XP) += ste10Xp.o obj-$(CONFIG_STE10XP) += ste10Xp.o
obj-$(CONFIG_MICREL_PHY) += micrel.o obj-$(CONFIG_MICREL_PHY) += micrel.o

99
drivers/net/phy/dp83848.c Normal file
View File

@ -0,0 +1,99 @@
/*
* Driver for the Texas Instruments DP83848 PHY
*
* Copyright (C) 2015 Texas Instruments 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.
*
* 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.
*/
#include <linux/module.h>
#include <linux/phy.h>
#define DP83848_PHY_ID 0x20005c90
/* Registers */
#define DP83848_MICR 0x11
#define DP83848_MISR 0x12
/* MICR Register Fields */
#define DP83848_MICR_INT_OE BIT(0) /* Interrupt Output Enable */
#define DP83848_MICR_INTEN BIT(1) /* Interrupt Enable */
/* MISR Register Fields */
#define DP83848_MISR_RHF_INT_EN BIT(0) /* Receive Error Counter */
#define DP83848_MISR_FHF_INT_EN BIT(1) /* False Carrier Counter */
#define DP83848_MISR_ANC_INT_EN BIT(2) /* Auto-negotiation complete */
#define DP83848_MISR_DUP_INT_EN BIT(3) /* Duplex Status */
#define DP83848_MISR_SPD_INT_EN BIT(4) /* Speed status */
#define DP83848_MISR_LINK_INT_EN BIT(5) /* Link status */
#define DP83848_MISR_ED_INT_EN BIT(6) /* Energy detect */
#define DP83848_MISR_LQM_INT_EN BIT(7) /* Link Quality Monitor */
static int dp83848_ack_interrupt(struct phy_device *phydev)
{
int err = phy_read(phydev, DP83848_MISR);
return err < 0 ? err : 0;
}
static int dp83848_config_intr(struct phy_device *phydev)
{
int err;
if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
err = phy_write(phydev, DP83848_MICR,
DP83848_MICR_INT_OE |
DP83848_MICR_INTEN);
if (err < 0)
return err;
return phy_write(phydev, DP83848_MISR,
DP83848_MISR_ANC_INT_EN |
DP83848_MISR_DUP_INT_EN |
DP83848_MISR_SPD_INT_EN |
DP83848_MISR_LINK_INT_EN);
}
return phy_write(phydev, DP83848_MICR, 0x0);
}
static struct mdio_device_id __maybe_unused dp83848_tbl[] = {
{ DP83848_PHY_ID, 0xfffffff0 },
{ }
};
MODULE_DEVICE_TABLE(mdio, dp83848_tbl);
static struct phy_driver dp83848_driver[] = {
{
.phy_id = DP83848_PHY_ID,
.phy_id_mask = 0xfffffff0,
.name = "TI DP83848",
.features = PHY_BASIC_FEATURES,
.flags = PHY_HAS_INTERRUPT,
.soft_reset = genphy_soft_reset,
.config_init = genphy_config_init,
.suspend = genphy_suspend,
.resume = genphy_resume,
.config_aneg = genphy_config_aneg,
.read_status = genphy_read_status,
/* IRQ related */
.ack_interrupt = dp83848_ack_interrupt,
.config_intr = dp83848_config_intr,
.driver = { .owner = THIS_MODULE, },
},
};
module_phy_driver(dp83848_driver);
MODULE_DESCRIPTION("Texas Instruments DP83848 PHY driver");
MODULE_AUTHOR("Andrew F. Davis <afd@ti.com");
MODULE_LICENSE("GPL");

View File

@ -514,6 +514,27 @@ static int ksz8873mll_read_status(struct phy_device *phydev)
return 0; return 0;
} }
static int ksz9031_read_status(struct phy_device *phydev)
{
int err;
int regval;
err = genphy_read_status(phydev);
if (err)
return err;
/* Make sure the PHY is not broken. Read idle error count,
* and reset the PHY if it is maxed out.
*/
regval = phy_read(phydev, MII_STAT1000);
if ((regval & 0xFF) == 0xFF) {
phy_init_hw(phydev);
phydev->link = 0;
}
return 0;
}
static int ksz8873mll_config_aneg(struct phy_device *phydev) static int ksz8873mll_config_aneg(struct phy_device *phydev)
{ {
return 0; return 0;
@ -772,7 +793,7 @@ static struct phy_driver ksphy_driver[] = {
.driver_data = &ksz9021_type, .driver_data = &ksz9021_type,
.config_init = ksz9031_config_init, .config_init = ksz9031_config_init,
.config_aneg = genphy_config_aneg, .config_aneg = genphy_config_aneg,
.read_status = genphy_read_status, .read_status = ksz9031_read_status,
.ack_interrupt = kszphy_ack_interrupt, .ack_interrupt = kszphy_ack_interrupt,
.config_intr = kszphy_config_intr, .config_intr = kszphy_config_intr,
.suspend = genphy_suspend, .suspend = genphy_suspend,

View File

@ -43,16 +43,25 @@ static int smsc_phy_ack_interrupt(struct phy_device *phydev)
static int smsc_phy_config_init(struct phy_device *phydev) static int smsc_phy_config_init(struct phy_device *phydev)
{ {
int __maybe_unused len;
struct device *dev __maybe_unused = &phydev->dev;
struct device_node *of_node __maybe_unused = dev->of_node;
int rc = phy_read(phydev, MII_LAN83C185_CTRL_STATUS); int rc = phy_read(phydev, MII_LAN83C185_CTRL_STATUS);
int enable_energy = 1;
if (rc < 0) if (rc < 0)
return rc; return rc;
/* Enable energy detect mode for this SMSC Transceivers */ if (of_find_property(of_node, "smsc,disable-energy-detect", &len))
rc = phy_write(phydev, MII_LAN83C185_CTRL_STATUS, enable_energy = 0;
rc | MII_LAN83C185_EDPWRDOWN);
if (rc < 0) if (enable_energy) {
return rc; /* Enable energy detect mode for this SMSC Transceivers */
rc = phy_write(phydev, MII_LAN83C185_CTRL_STATUS,
rc | MII_LAN83C185_EDPWRDOWN);
if (rc < 0)
return rc;
}
return smsc_phy_ack_interrupt(phydev); return smsc_phy_ack_interrupt(phydev);
} }

View File

@ -589,7 +589,7 @@ static int pppoe_release(struct socket *sock)
po = pppox_sk(sk); po = pppox_sk(sk);
if (sk->sk_state & (PPPOX_CONNECTED | PPPOX_BOUND | PPPOX_ZOMBIE)) { if (po->pppoe_dev) {
dev_put(po->pppoe_dev); dev_put(po->pppoe_dev);
po->pppoe_dev = NULL; po->pppoe_dev = NULL;
} }

View File

@ -711,6 +711,10 @@ static const struct usb_device_id products[] = {
{QMI_FIXED_INTF(0x1199, 0x9056, 8)}, /* Sierra Wireless Modem */ {QMI_FIXED_INTF(0x1199, 0x9056, 8)}, /* Sierra Wireless Modem */
{QMI_FIXED_INTF(0x1199, 0x9057, 8)}, {QMI_FIXED_INTF(0x1199, 0x9057, 8)},
{QMI_FIXED_INTF(0x1199, 0x9061, 8)}, /* Sierra Wireless Modem */ {QMI_FIXED_INTF(0x1199, 0x9061, 8)}, /* Sierra Wireless Modem */
{QMI_FIXED_INTF(0x1199, 0x9070, 8)}, /* Sierra Wireless MC74xx/EM74xx */
{QMI_FIXED_INTF(0x1199, 0x9070, 10)}, /* Sierra Wireless MC74xx/EM74xx */
{QMI_FIXED_INTF(0x1199, 0x9071, 8)}, /* Sierra Wireless MC74xx/EM74xx */
{QMI_FIXED_INTF(0x1199, 0x9071, 10)}, /* Sierra Wireless MC74xx/EM74xx */
{QMI_FIXED_INTF(0x1bbb, 0x011e, 4)}, /* Telekom Speedstick LTE II (Alcatel One Touch L100V LTE) */ {QMI_FIXED_INTF(0x1bbb, 0x011e, 4)}, /* Telekom Speedstick LTE II (Alcatel One Touch L100V LTE) */
{QMI_FIXED_INTF(0x1bbb, 0x0203, 2)}, /* Alcatel L800MA */ {QMI_FIXED_INTF(0x1bbb, 0x0203, 2)}, /* Alcatel L800MA */
{QMI_FIXED_INTF(0x2357, 0x0201, 4)}, /* TP-LINK HSUPA Modem MA180 */ {QMI_FIXED_INTF(0x2357, 0x0201, 4)}, /* TP-LINK HSUPA Modem MA180 */

View File

@ -2360,6 +2360,46 @@ static int vxlan_change_mtu(struct net_device *dev, int new_mtu)
return 0; return 0;
} }
static int egress_ipv4_tun_info(struct net_device *dev, struct sk_buff *skb,
struct ip_tunnel_info *info,
__be16 sport, __be16 dport)
{
struct vxlan_dev *vxlan = netdev_priv(dev);
struct rtable *rt;
struct flowi4 fl4;
memset(&fl4, 0, sizeof(fl4));
fl4.flowi4_tos = RT_TOS(info->key.tos);
fl4.flowi4_mark = skb->mark;
fl4.flowi4_proto = IPPROTO_UDP;
fl4.daddr = info->key.u.ipv4.dst;
rt = ip_route_output_key(vxlan->net, &fl4);
if (IS_ERR(rt))
return PTR_ERR(rt);
ip_rt_put(rt);
info->key.u.ipv4.src = fl4.saddr;
info->key.tp_src = sport;
info->key.tp_dst = dport;
return 0;
}
static int vxlan_fill_metadata_dst(struct net_device *dev, struct sk_buff *skb)
{
struct vxlan_dev *vxlan = netdev_priv(dev);
struct ip_tunnel_info *info = skb_tunnel_info(skb);
__be16 sport, dport;
sport = udp_flow_src_port(dev_net(dev), skb, vxlan->cfg.port_min,
vxlan->cfg.port_max, true);
dport = info->key.tp_dst ? : vxlan->cfg.dst_port;
if (ip_tunnel_info_af(info) == AF_INET)
return egress_ipv4_tun_info(dev, skb, info, sport, dport);
return -EINVAL;
}
static const struct net_device_ops vxlan_netdev_ops = { static const struct net_device_ops vxlan_netdev_ops = {
.ndo_init = vxlan_init, .ndo_init = vxlan_init,
.ndo_uninit = vxlan_uninit, .ndo_uninit = vxlan_uninit,
@ -2374,6 +2414,7 @@ static const struct net_device_ops vxlan_netdev_ops = {
.ndo_fdb_add = vxlan_fdb_add, .ndo_fdb_add = vxlan_fdb_add,
.ndo_fdb_del = vxlan_fdb_delete, .ndo_fdb_del = vxlan_fdb_delete,
.ndo_fdb_dump = vxlan_fdb_dump, .ndo_fdb_dump = vxlan_fdb_dump,
.ndo_fill_metadata_dst = vxlan_fill_metadata_dst,
}; };
/* Info for udev, that this is a virtual tunnel endpoint */ /* Info for udev, that this is a virtual tunnel endpoint */

View File

@ -1706,19 +1706,19 @@ static void xennet_destroy_queues(struct netfront_info *info)
} }
static int xennet_create_queues(struct netfront_info *info, static int xennet_create_queues(struct netfront_info *info,
unsigned int num_queues) unsigned int *num_queues)
{ {
unsigned int i; unsigned int i;
int ret; int ret;
info->queues = kcalloc(num_queues, sizeof(struct netfront_queue), info->queues = kcalloc(*num_queues, sizeof(struct netfront_queue),
GFP_KERNEL); GFP_KERNEL);
if (!info->queues) if (!info->queues)
return -ENOMEM; return -ENOMEM;
rtnl_lock(); rtnl_lock();
for (i = 0; i < num_queues; i++) { for (i = 0; i < *num_queues; i++) {
struct netfront_queue *queue = &info->queues[i]; struct netfront_queue *queue = &info->queues[i];
queue->id = i; queue->id = i;
@ -1728,7 +1728,7 @@ static int xennet_create_queues(struct netfront_info *info,
if (ret < 0) { if (ret < 0) {
dev_warn(&info->netdev->dev, dev_warn(&info->netdev->dev,
"only created %d queues\n", i); "only created %d queues\n", i);
num_queues = i; *num_queues = i;
break; break;
} }
@ -1738,11 +1738,11 @@ static int xennet_create_queues(struct netfront_info *info,
napi_enable(&queue->napi); napi_enable(&queue->napi);
} }
netif_set_real_num_tx_queues(info->netdev, num_queues); netif_set_real_num_tx_queues(info->netdev, *num_queues);
rtnl_unlock(); rtnl_unlock();
if (num_queues == 0) { if (*num_queues == 0) {
dev_err(&info->netdev->dev, "no queues\n"); dev_err(&info->netdev->dev, "no queues\n");
return -EINVAL; return -EINVAL;
} }
@ -1788,7 +1788,7 @@ static int talk_to_netback(struct xenbus_device *dev,
if (info->queues) if (info->queues)
xennet_destroy_queues(info); xennet_destroy_queues(info);
err = xennet_create_queues(info, num_queues); err = xennet_create_queues(info, &num_queues);
if (err < 0) if (err < 0)
goto destroy_ring; goto destroy_ring;

View File

@ -237,6 +237,10 @@
#define KASAN_ABI_VERSION 3 #define KASAN_ABI_VERSION 3
#endif #endif
#if GCC_VERSION >= 50000
#define CC_HAVE_BUILTIN_OVERFLOW
#endif
#endif /* gcc version >= 40000 specific checks */ #endif /* gcc version >= 40000 specific checks */
#if !defined(__noclone) #if !defined(__noclone)

View File

@ -1055,6 +1055,10 @@ typedef u16 (*select_queue_fallback_t)(struct net_device *dev,
* This function is used to pass protocol port error state information * This function is used to pass protocol port error state information
* to the switch driver. The switch driver can react to the proto_down * to the switch driver. The switch driver can react to the proto_down
* by doing a phys down on the associated switch port. * by doing a phys down on the associated switch port.
* int (*ndo_fill_metadata_dst)(struct net_device *dev, struct sk_buff *skb);
* This function is used to get egress tunnel information for given skb.
* This is useful for retrieving outer tunnel header parameters while
* sampling packet.
* *
*/ */
struct net_device_ops { struct net_device_ops {
@ -1230,6 +1234,8 @@ struct net_device_ops {
int (*ndo_get_iflink)(const struct net_device *dev); int (*ndo_get_iflink)(const struct net_device *dev);
int (*ndo_change_proto_down)(struct net_device *dev, int (*ndo_change_proto_down)(struct net_device *dev,
bool proto_down); bool proto_down);
int (*ndo_fill_metadata_dst)(struct net_device *dev,
struct sk_buff *skb);
}; };
/** /**
@ -2210,6 +2216,7 @@ void dev_add_offload(struct packet_offload *po);
void dev_remove_offload(struct packet_offload *po); void dev_remove_offload(struct packet_offload *po);
int dev_get_iflink(const struct net_device *dev); int dev_get_iflink(const struct net_device *dev);
int dev_fill_metadata_dst(struct net_device *dev, struct sk_buff *skb);
struct net_device *__dev_get_by_flags(struct net *net, unsigned short flags, struct net_device *__dev_get_by_flags(struct net *net, unsigned short flags,
unsigned short mask); unsigned short mask);
struct net_device *dev_get_by_name(struct net *net, const char *name); struct net_device *dev_get_by_name(struct net *net, const char *name);

View File

@ -0,0 +1,18 @@
#pragma once
#include <linux/kernel.h>
#ifdef CC_HAVE_BUILTIN_OVERFLOW
#define overflow_usub __builtin_usub_overflow
#else
static inline bool overflow_usub(unsigned int a, unsigned int b,
unsigned int *res)
{
*res = a - b;
return *res > a ? true : false;
}
#endif

View File

@ -60,6 +60,38 @@ static inline struct metadata_dst *tun_rx_dst(int md_size)
return tun_dst; return tun_dst;
} }
static inline struct metadata_dst *tun_dst_unclone(struct sk_buff *skb)
{
struct metadata_dst *md_dst = skb_metadata_dst(skb);
int md_size = md_dst->u.tun_info.options_len;
struct metadata_dst *new_md;
if (!md_dst)
return ERR_PTR(-EINVAL);
new_md = metadata_dst_alloc(md_size, GFP_ATOMIC);
if (!new_md)
return ERR_PTR(-ENOMEM);
memcpy(&new_md->u.tun_info, &md_dst->u.tun_info,
sizeof(struct ip_tunnel_info) + md_size);
skb_dst_drop(skb);
dst_hold(&new_md->dst);
skb_dst_set(skb, &new_md->dst);
return new_md;
}
static inline struct ip_tunnel_info *skb_tunnel_info_unclone(struct sk_buff *skb)
{
struct metadata_dst *dst;
dst = tun_dst_unclone(skb);
if (IS_ERR(dst))
return NULL;
return &dst->u.tun_info;
}
static inline struct metadata_dst *ip_tun_rx_dst(struct sk_buff *skb, static inline struct metadata_dst *ip_tun_rx_dst(struct sk_buff *skb,
__be16 flags, __be16 flags,
__be64 tunnel_id, __be64 tunnel_id,

View File

@ -622,7 +622,8 @@ struct ovs_action_hash {
* enum ovs_ct_attr - Attributes for %OVS_ACTION_ATTR_CT action. * enum ovs_ct_attr - Attributes for %OVS_ACTION_ATTR_CT action.
* @OVS_CT_ATTR_COMMIT: If present, commits the connection to the conntrack * @OVS_CT_ATTR_COMMIT: If present, commits the connection to the conntrack
* table. This allows future packets for the same connection to be identified * table. This allows future packets for the same connection to be identified
* as 'established' or 'related'. * as 'established' or 'related'. The flow key for the current packet will
* retain the pre-commit connection state.
* @OVS_CT_ATTR_ZONE: u16 connection tracking zone. * @OVS_CT_ATTR_ZONE: u16 connection tracking zone.
* @OVS_CT_ATTR_MARK: u32 value followed by u32 mask. For each bit set in the * @OVS_CT_ATTR_MARK: u32 value followed by u32 mask. For each bit set in the
* mask, the corresponding bit in the value is copied to the connection * mask, the corresponding bit in the value is copied to the connection

View File

@ -99,6 +99,7 @@
#include <linux/rtnetlink.h> #include <linux/rtnetlink.h>
#include <linux/stat.h> #include <linux/stat.h>
#include <net/dst.h> #include <net/dst.h>
#include <net/dst_metadata.h>
#include <net/pkt_sched.h> #include <net/pkt_sched.h>
#include <net/checksum.h> #include <net/checksum.h>
#include <net/xfrm.h> #include <net/xfrm.h>
@ -681,6 +682,32 @@ int dev_get_iflink(const struct net_device *dev)
} }
EXPORT_SYMBOL(dev_get_iflink); EXPORT_SYMBOL(dev_get_iflink);
/**
* dev_fill_metadata_dst - Retrieve tunnel egress information.
* @dev: targeted interface
* @skb: The packet.
*
* For better visibility of tunnel traffic OVS needs to retrieve
* egress tunnel information for a packet. Following API allows
* user to get this info.
*/
int dev_fill_metadata_dst(struct net_device *dev, struct sk_buff *skb)
{
struct ip_tunnel_info *info;
if (!dev->netdev_ops || !dev->netdev_ops->ndo_fill_metadata_dst)
return -EINVAL;
info = skb_tunnel_info_unclone(skb);
if (!info)
return -ENOMEM;
if (unlikely(!(info->mode & IP_TUNNEL_INFO_TX)))
return -EINVAL;
return dev->netdev_ops->ndo_fill_metadata_dst(dev, skb);
}
EXPORT_SYMBOL_GPL(dev_fill_metadata_dst);
/** /**
* __dev_get_by_name - find a device by its name * __dev_get_by_name - find a device by its name
* @net: the applicable net namespace * @net: the applicable net namespace

View File

@ -498,10 +498,26 @@ static struct sk_buff *gre_handle_offloads(struct sk_buff *skb,
csum ? SKB_GSO_GRE_CSUM : SKB_GSO_GRE); csum ? SKB_GSO_GRE_CSUM : SKB_GSO_GRE);
} }
static struct rtable *gre_get_rt(struct sk_buff *skb,
struct net_device *dev,
struct flowi4 *fl,
const struct ip_tunnel_key *key)
{
struct net *net = dev_net(dev);
memset(fl, 0, sizeof(*fl));
fl->daddr = key->u.ipv4.dst;
fl->saddr = key->u.ipv4.src;
fl->flowi4_tos = RT_TOS(key->tos);
fl->flowi4_mark = skb->mark;
fl->flowi4_proto = IPPROTO_GRE;
return ip_route_output_key(net, fl);
}
static void gre_fb_xmit(struct sk_buff *skb, struct net_device *dev) static void gre_fb_xmit(struct sk_buff *skb, struct net_device *dev)
{ {
struct ip_tunnel_info *tun_info; struct ip_tunnel_info *tun_info;
struct net *net = dev_net(dev);
const struct ip_tunnel_key *key; const struct ip_tunnel_key *key;
struct flowi4 fl; struct flowi4 fl;
struct rtable *rt; struct rtable *rt;
@ -516,14 +532,7 @@ static void gre_fb_xmit(struct sk_buff *skb, struct net_device *dev)
goto err_free_skb; goto err_free_skb;
key = &tun_info->key; key = &tun_info->key;
memset(&fl, 0, sizeof(fl)); rt = gre_get_rt(skb, dev, &fl, key);
fl.daddr = key->u.ipv4.dst;
fl.saddr = key->u.ipv4.src;
fl.flowi4_tos = RT_TOS(key->tos);
fl.flowi4_mark = skb->mark;
fl.flowi4_proto = IPPROTO_GRE;
rt = ip_route_output_key(net, &fl);
if (IS_ERR(rt)) if (IS_ERR(rt))
goto err_free_skb; goto err_free_skb;
@ -566,6 +575,24 @@ err_free_skb:
dev->stats.tx_dropped++; dev->stats.tx_dropped++;
} }
static int gre_fill_metadata_dst(struct net_device *dev, struct sk_buff *skb)
{
struct ip_tunnel_info *info = skb_tunnel_info(skb);
struct rtable *rt;
struct flowi4 fl4;
if (ip_tunnel_info_af(info) != AF_INET)
return -EINVAL;
rt = gre_get_rt(skb, dev, &fl4, &info->key);
if (IS_ERR(rt))
return PTR_ERR(rt);
ip_rt_put(rt);
info->key.u.ipv4.src = fl4.saddr;
return 0;
}
static netdev_tx_t ipgre_xmit(struct sk_buff *skb, static netdev_tx_t ipgre_xmit(struct sk_buff *skb,
struct net_device *dev) struct net_device *dev)
{ {
@ -1023,6 +1050,7 @@ static const struct net_device_ops gre_tap_netdev_ops = {
.ndo_change_mtu = ip_tunnel_change_mtu, .ndo_change_mtu = ip_tunnel_change_mtu,
.ndo_get_stats64 = ip_tunnel_get_stats64, .ndo_get_stats64 = ip_tunnel_get_stats64,
.ndo_get_iflink = ip_tunnel_get_iflink, .ndo_get_iflink = ip_tunnel_get_iflink,
.ndo_fill_metadata_dst = gre_fill_metadata_dst,
}; };
static void ipgre_tap_setup(struct net_device *dev) static void ipgre_tap_setup(struct net_device *dev)

View File

@ -75,6 +75,7 @@ endif # NF_TABLES
config NF_DUP_IPV4 config NF_DUP_IPV4
tristate "Netfilter IPv4 packet duplication to alternate destination" tristate "Netfilter IPv4 packet duplication to alternate destination"
depends on !NF_CONNTRACK || NF_CONNTRACK
help help
This option enables the nf_dup_ipv4 core, which duplicates an IPv4 This option enables the nf_dup_ipv4 core, which duplicates an IPv4
packet to be rerouted to another destination. packet to be rerouted to another destination.

View File

@ -60,9 +60,7 @@ static bool rpfilter_lookup_reverse(struct net *net, struct flowi4 *fl4,
if (FIB_RES_DEV(res) == dev) if (FIB_RES_DEV(res) == dev)
dev_match = true; dev_match = true;
#endif #endif
if (dev_match || flags & XT_RPFILTER_LOOSE) return dev_match || flags & XT_RPFILTER_LOOSE;
return FIB_RES_NH(res).nh_scope <= RT_SCOPE_HOST;
return dev_match;
} }
static bool rpfilter_is_local(const struct sk_buff *skb) static bool rpfilter_is_local(const struct sk_buff *skb)

View File

@ -209,7 +209,7 @@ static void dctcp_update_alpha(struct sock *sk, u32 flags)
/* alpha = (1 - g) * alpha + g * F */ /* alpha = (1 - g) * alpha + g * F */
alpha -= alpha >> dctcp_shift_g; alpha -= min_not_zero(alpha, alpha >> dctcp_shift_g);
if (bytes_ecn) { if (bytes_ecn) {
/* If dctcp_shift_g == 1, a 32bit value would overflow /* If dctcp_shift_g == 1, a 32bit value would overflow
* after 8 Mbytes. * after 8 Mbytes.

View File

@ -3410,7 +3410,7 @@ static int tcp_xmit_probe_skb(struct sock *sk, int urgent, int mib)
*/ */
tcp_init_nondata_skb(skb, tp->snd_una - !urgent, TCPHDR_ACK); tcp_init_nondata_skb(skb, tp->snd_una - !urgent, TCPHDR_ACK);
skb_mstamp_get(&skb->skb_mstamp); skb_mstamp_get(&skb->skb_mstamp);
NET_INC_STATS_BH(sock_net(sk), mib); NET_INC_STATS(sock_net(sk), mib);
return tcp_transmit_skb(sk, skb, 0, GFP_ATOMIC); return tcp_transmit_skb(sk, skb, 0, GFP_ATOMIC);
} }

View File

@ -30,6 +30,8 @@ static int xfrm4_tunnel_check_size(struct sk_buff *skb)
mtu = dst_mtu(skb_dst(skb)); mtu = dst_mtu(skb_dst(skb));
if (skb->len > mtu) { if (skb->len > mtu) {
skb->protocol = htons(ETH_P_IP);
if (skb->sk) if (skb->sk)
xfrm_local_error(skb, mtu); xfrm_local_error(skb, mtu);
else else

View File

@ -32,6 +32,7 @@ struct fib6_rule {
struct dst_entry *fib6_rule_lookup(struct net *net, struct flowi6 *fl6, struct dst_entry *fib6_rule_lookup(struct net *net, struct flowi6 *fl6,
int flags, pol_lookup_t lookup) int flags, pol_lookup_t lookup)
{ {
struct rt6_info *rt;
struct fib_lookup_arg arg = { struct fib_lookup_arg arg = {
.lookup_ptr = lookup, .lookup_ptr = lookup,
.flags = FIB_LOOKUP_NOREF, .flags = FIB_LOOKUP_NOREF,
@ -40,11 +41,21 @@ struct dst_entry *fib6_rule_lookup(struct net *net, struct flowi6 *fl6,
fib_rules_lookup(net->ipv6.fib6_rules_ops, fib_rules_lookup(net->ipv6.fib6_rules_ops,
flowi6_to_flowi(fl6), flags, &arg); flowi6_to_flowi(fl6), flags, &arg);
if (arg.result) rt = arg.result;
return arg.result;
dst_hold(&net->ipv6.ip6_null_entry->dst); if (!rt) {
return &net->ipv6.ip6_null_entry->dst; dst_hold(&net->ipv6.ip6_null_entry->dst);
return &net->ipv6.ip6_null_entry->dst;
}
if (rt->rt6i_flags & RTF_REJECT &&
rt->dst.error == -EAGAIN) {
ip6_rt_put(rt);
rt = net->ipv6.ip6_null_entry;
dst_hold(&rt->dst);
}
return &rt->dst;
} }
static int fib6_rule_action(struct fib_rule *rule, struct flowi *flp, static int fib6_rule_action(struct fib_rule *rule, struct flowi *flp,

View File

@ -286,7 +286,17 @@ struct fib6_table *fib6_get_table(struct net *net, u32 id)
struct dst_entry *fib6_rule_lookup(struct net *net, struct flowi6 *fl6, struct dst_entry *fib6_rule_lookup(struct net *net, struct flowi6 *fl6,
int flags, pol_lookup_t lookup) int flags, pol_lookup_t lookup)
{ {
return (struct dst_entry *) lookup(net, net->ipv6.fib6_main_tbl, fl6, flags); struct rt6_info *rt;
rt = lookup(net, net->ipv6.fib6_main_tbl, fl6, flags);
if (rt->rt6i_flags & RTF_REJECT &&
rt->dst.error == -EAGAIN) {
ip6_rt_put(rt);
rt = net->ipv6.ip6_null_entry;
dst_hold(&rt->dst);
}
return &rt->dst;
} }
static void __net_init fib6_tables_init(struct net *net) static void __net_init fib6_tables_init(struct net *net)

View File

@ -28,6 +28,7 @@
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/overflow-arith.h>
#include <linux/string.h> #include <linux/string.h>
#include <linux/socket.h> #include <linux/socket.h>
#include <linux/net.h> #include <linux/net.h>
@ -596,7 +597,10 @@ int ip6_fragment(struct net *net, struct sock *sk, struct sk_buff *skb,
if (np->frag_size) if (np->frag_size)
mtu = np->frag_size; mtu = np->frag_size;
} }
mtu -= hlen + sizeof(struct frag_hdr);
if (overflow_usub(mtu, hlen + sizeof(struct frag_hdr), &mtu) ||
mtu <= 7)
goto fail_toobig;
frag_id = ipv6_select_ident(net, &ipv6_hdr(skb)->daddr, frag_id = ipv6_select_ident(net, &ipv6_hdr(skb)->daddr,
&ipv6_hdr(skb)->saddr); &ipv6_hdr(skb)->saddr);

View File

@ -58,6 +58,7 @@ endif # NF_TABLES
config NF_DUP_IPV6 config NF_DUP_IPV6
tristate "Netfilter IPv6 packet duplication to alternate destination" tristate "Netfilter IPv6 packet duplication to alternate destination"
depends on !NF_CONNTRACK || NF_CONNTRACK
help help
This option enables the nf_dup_ipv6 core, which duplicates an IPv6 This option enables the nf_dup_ipv6 core, which duplicates an IPv6
packet to be rerouted to another destination. packet to be rerouted to another destination.

View File

@ -1171,6 +1171,7 @@ struct dst_entry *ip6_route_output(struct net *net, const struct sock *sk,
{ {
struct dst_entry *dst; struct dst_entry *dst;
int flags = 0; int flags = 0;
bool any_src;
dst = l3mdev_rt6_dst_by_oif(net, fl6); dst = l3mdev_rt6_dst_by_oif(net, fl6);
if (dst) if (dst)
@ -1178,11 +1179,12 @@ struct dst_entry *ip6_route_output(struct net *net, const struct sock *sk,
fl6->flowi6_iif = LOOPBACK_IFINDEX; fl6->flowi6_iif = LOOPBACK_IFINDEX;
any_src = ipv6_addr_any(&fl6->saddr);
if ((sk && sk->sk_bound_dev_if) || rt6_need_strict(&fl6->daddr) || if ((sk && sk->sk_bound_dev_if) || rt6_need_strict(&fl6->daddr) ||
fl6->flowi6_oif) (fl6->flowi6_oif && any_src))
flags |= RT6_LOOKUP_F_IFACE; flags |= RT6_LOOKUP_F_IFACE;
if (!ipv6_addr_any(&fl6->saddr)) if (!any_src)
flags |= RT6_LOOKUP_F_HAS_SADDR; flags |= RT6_LOOKUP_F_HAS_SADDR;
else if (sk) else if (sk)
flags |= rt6_srcprefs2flags(inet6_sk(sk)->srcprefs); flags |= rt6_srcprefs2flags(inet6_sk(sk)->srcprefs);

View File

@ -79,6 +79,7 @@ static int xfrm6_tunnel_check_size(struct sk_buff *skb)
if (!skb->ignore_df && skb->len > mtu) { if (!skb->ignore_df && skb->len > mtu) {
skb->dev = dst->dev; skb->dev = dst->dev;
skb->protocol = htons(ETH_P_IPV6);
if (xfrm6_local_dontfrag(skb)) if (xfrm6_local_dontfrag(skb))
xfrm6_local_rxpmtu(skb, mtu); xfrm6_local_rxpmtu(skb, mtu);
@ -143,6 +144,7 @@ static int __xfrm6_output(struct net *net, struct sock *sk, struct sk_buff *skb)
struct dst_entry *dst = skb_dst(skb); struct dst_entry *dst = skb_dst(skb);
struct xfrm_state *x = dst->xfrm; struct xfrm_state *x = dst->xfrm;
int mtu; int mtu;
bool toobig;
#ifdef CONFIG_NETFILTER #ifdef CONFIG_NETFILTER
if (!x) { if (!x) {
@ -151,25 +153,29 @@ static int __xfrm6_output(struct net *net, struct sock *sk, struct sk_buff *skb)
} }
#endif #endif
if (x->props.mode != XFRM_MODE_TUNNEL)
goto skip_frag;
if (skb->protocol == htons(ETH_P_IPV6)) if (skb->protocol == htons(ETH_P_IPV6))
mtu = ip6_skb_dst_mtu(skb); mtu = ip6_skb_dst_mtu(skb);
else else
mtu = dst_mtu(skb_dst(skb)); mtu = dst_mtu(skb_dst(skb));
if (skb->len > mtu && xfrm6_local_dontfrag(skb)) { toobig = skb->len > mtu && !skb_is_gso(skb);
if (toobig && xfrm6_local_dontfrag(skb)) {
xfrm6_local_rxpmtu(skb, mtu); xfrm6_local_rxpmtu(skb, mtu);
return -EMSGSIZE; return -EMSGSIZE;
} else if (!skb->ignore_df && skb->len > mtu && skb->sk) { } else if (!skb->ignore_df && toobig && skb->sk) {
xfrm_local_error(skb, mtu); xfrm_local_error(skb, mtu);
return -EMSGSIZE; return -EMSGSIZE;
} }
if (x->props.mode == XFRM_MODE_TUNNEL && if (toobig || dst_allfrag(skb_dst(skb)))
((skb->len > mtu && !skb_is_gso(skb)) ||
dst_allfrag(skb_dst(skb)))) {
return ip6_fragment(net, sk, skb, return ip6_fragment(net, sk, skb,
__xfrm6_output_finish); __xfrm6_output_finish);
}
skip_frag:
return x->outer_mode->afinfo->output_finish(sk, skb); return x->outer_mode->afinfo->output_finish(sk, skb);
} }

View File

@ -177,7 +177,8 @@ _decode_session6(struct sk_buff *skb, struct flowi *fl, int reverse)
return; return;
case IPPROTO_ICMPV6: case IPPROTO_ICMPV6:
if (!onlyproto && pskb_may_pull(skb, nh + offset + 2 - skb->data)) { if (!onlyproto && (nh + offset + 2 < skb->data ||
pskb_may_pull(skb, nh + offset + 2 - skb->data))) {
u8 *icmp; u8 *icmp;
nh = skb_network_header(skb); nh = skb_network_header(skb);
@ -191,7 +192,8 @@ _decode_session6(struct sk_buff *skb, struct flowi *fl, int reverse)
#if IS_ENABLED(CONFIG_IPV6_MIP6) #if IS_ENABLED(CONFIG_IPV6_MIP6)
case IPPROTO_MH: case IPPROTO_MH:
offset += ipv6_optlen(exthdr); offset += ipv6_optlen(exthdr);
if (!onlyproto && pskb_may_pull(skb, nh + offset + 3 - skb->data)) { if (!onlyproto && (nh + offset + 3 < skb->data ||
pskb_may_pull(skb, nh + offset + 3 - skb->data))) {
struct ip6_mh *mh; struct ip6_mh *mh;
nh = skb_network_header(skb); nh = skb_network_header(skb);

View File

@ -1839,7 +1839,7 @@ static void *irlmp_seq_hb_idx(struct irlmp_iter_state *iter, loff_t *off)
for (element = hashbin_get_first(iter->hashbin); for (element = hashbin_get_first(iter->hashbin);
element != NULL; element != NULL;
element = hashbin_get_next(iter->hashbin)) { element = hashbin_get_next(iter->hashbin)) {
if (!off || *off-- == 0) { if (!off || (*off)-- == 0) {
/* NB: hashbin left locked */ /* NB: hashbin left locked */
return element; return element;
} }

View File

@ -261,7 +261,7 @@ static int pfkey_broadcast(struct sk_buff *skb,
err2 = pfkey_broadcast_one(skb, &skb2, GFP_ATOMIC, sk); err2 = pfkey_broadcast_one(skb, &skb2, GFP_ATOMIC, sk);
/* Error is cleare after succecful sending to at least one /* Error is cleared after successful sending to at least one
* registered KM */ * registered KM */
if ((broadcast_flags & BROADCAST_REGISTERED) && err) if ((broadcast_flags & BROADCAST_REGISTERED) && err)
err = err2; err = err2;

View File

@ -152,6 +152,8 @@ void nf_unregister_net_hook(struct net *net, const struct nf_hook_ops *reg)
#endif #endif
synchronize_net(); synchronize_net();
nf_queue_nf_hook_drop(net, &entry->ops); nf_queue_nf_hook_drop(net, &entry->ops);
/* other cpu might still process nfqueue verdict that used reg */
synchronize_net();
kfree(entry); kfree(entry);
} }
EXPORT_SYMBOL(nf_unregister_net_hook); EXPORT_SYMBOL(nf_unregister_net_hook);

View File

@ -297,7 +297,7 @@ list_set_uadd(struct ip_set *set, void *value, const struct ip_set_ext *ext,
ip_set_timeout_expired(ext_timeout(n, set)))) ip_set_timeout_expired(ext_timeout(n, set))))
n = NULL; n = NULL;
e = kzalloc(set->dsize, GFP_KERNEL); e = kzalloc(set->dsize, GFP_ATOMIC);
if (!e) if (!e)
return -ENOMEM; return -ENOMEM;
e->id = d->id; e->id = d->id;

View File

@ -2371,7 +2371,7 @@ static int netlink_getsockopt(struct socket *sock, int level, int optname,
int pos, idx, shift; int pos, idx, shift;
err = 0; err = 0;
netlink_table_grab(); netlink_lock_table();
for (pos = 0; pos * 8 < nlk->ngroups; pos += sizeof(u32)) { for (pos = 0; pos * 8 < nlk->ngroups; pos += sizeof(u32)) {
if (len - pos < sizeof(u32)) if (len - pos < sizeof(u32))
break; break;
@ -2386,7 +2386,7 @@ static int netlink_getsockopt(struct socket *sock, int level, int optname,
} }
if (put_user(ALIGN(nlk->ngroups / 8, sizeof(u32)), optlen)) if (put_user(ALIGN(nlk->ngroups / 8, sizeof(u32)), optlen))
err = -EFAULT; err = -EFAULT;
netlink_table_ungrab(); netlink_unlock_table();
break; break;
} }
case NETLINK_CAP_ACK: case NETLINK_CAP_ACK:

View File

@ -769,7 +769,6 @@ static int output_userspace(struct datapath *dp, struct sk_buff *skb,
struct sw_flow_key *key, const struct nlattr *attr, struct sw_flow_key *key, const struct nlattr *attr,
const struct nlattr *actions, int actions_len) const struct nlattr *actions, int actions_len)
{ {
struct ip_tunnel_info info;
struct dp_upcall_info upcall; struct dp_upcall_info upcall;
const struct nlattr *a; const struct nlattr *a;
int rem; int rem;
@ -797,11 +796,9 @@ static int output_userspace(struct datapath *dp, struct sk_buff *skb,
if (vport) { if (vport) {
int err; int err;
upcall.egress_tun_info = &info; err = dev_fill_metadata_dst(vport->dev, skb);
err = ovs_vport_get_egress_tun_info(vport, skb, if (!err)
&upcall); upcall.egress_tun_info = skb_tunnel_info(skb);
if (err)
upcall.egress_tun_info = NULL;
} }
break; break;

View File

@ -151,6 +151,8 @@ static void ovs_ct_update_key(const struct sk_buff *skb,
ct = nf_ct_get(skb, &ctinfo); ct = nf_ct_get(skb, &ctinfo);
if (ct) { if (ct) {
state = ovs_ct_get_state(ctinfo); state = ovs_ct_get_state(ctinfo);
if (!nf_ct_is_confirmed(ct))
state |= OVS_CS_F_NEW;
if (ct->master) if (ct->master)
state |= OVS_CS_F_RELATED; state |= OVS_CS_F_RELATED;
zone = nf_ct_zone(ct); zone = nf_ct_zone(ct);
@ -222,9 +224,6 @@ static int ovs_ct_set_labels(struct sk_buff *skb, struct sw_flow_key *key,
struct nf_conn *ct; struct nf_conn *ct;
int err; int err;
if (!IS_ENABLED(CONFIG_NF_CONNTRACK_LABELS))
return -ENOTSUPP;
/* The connection could be invalid, in which case set_label is no-op.*/ /* The connection could be invalid, in which case set_label is no-op.*/
ct = nf_ct_get(skb, &ctinfo); ct = nf_ct_get(skb, &ctinfo);
if (!ct) if (!ct)
@ -377,7 +376,7 @@ static bool skb_nfct_cached(const struct net *net, const struct sk_buff *skb,
return true; return true;
} }
static int __ovs_ct_lookup(struct net *net, const struct sw_flow_key *key, static int __ovs_ct_lookup(struct net *net, struct sw_flow_key *key,
const struct ovs_conntrack_info *info, const struct ovs_conntrack_info *info,
struct sk_buff *skb) struct sk_buff *skb)
{ {
@ -408,6 +407,8 @@ static int __ovs_ct_lookup(struct net *net, const struct sw_flow_key *key,
} }
} }
ovs_ct_update_key(skb, key, true);
return 0; return 0;
} }
@ -430,8 +431,6 @@ static int ovs_ct_lookup(struct net *net, struct sw_flow_key *key,
err = __ovs_ct_lookup(net, key, info, skb); err = __ovs_ct_lookup(net, key, info, skb);
if (err) if (err)
return err; return err;
ovs_ct_update_key(skb, key, true);
} }
return 0; return 0;
@ -460,8 +459,6 @@ static int ovs_ct_commit(struct net *net, struct sw_flow_key *key,
if (nf_conntrack_confirm(skb) != NF_ACCEPT) if (nf_conntrack_confirm(skb) != NF_ACCEPT)
return -EINVAL; return -EINVAL;
ovs_ct_update_key(skb, key, true);
return 0; return 0;
} }
@ -587,6 +584,10 @@ static int parse_ct(const struct nlattr *attr, struct ovs_conntrack_info *info,
case OVS_CT_ATTR_MARK: { case OVS_CT_ATTR_MARK: {
struct md_mark *mark = nla_data(a); struct md_mark *mark = nla_data(a);
if (!mark->mask) {
OVS_NLERR(log, "ct_mark mask cannot be 0");
return -EINVAL;
}
info->mark = *mark; info->mark = *mark;
break; break;
} }
@ -595,6 +596,10 @@ static int parse_ct(const struct nlattr *attr, struct ovs_conntrack_info *info,
case OVS_CT_ATTR_LABELS: { case OVS_CT_ATTR_LABELS: {
struct md_labels *labels = nla_data(a); struct md_labels *labels = nla_data(a);
if (!labels_nonzero(&labels->mask)) {
OVS_NLERR(log, "ct_labels mask cannot be 0");
return -EINVAL;
}
info->labels = *labels; info->labels = *labels;
break; break;
} }
@ -705,11 +710,12 @@ int ovs_ct_action_to_attr(const struct ovs_conntrack_info *ct_info,
if (IS_ENABLED(CONFIG_NF_CONNTRACK_ZONES) && if (IS_ENABLED(CONFIG_NF_CONNTRACK_ZONES) &&
nla_put_u16(skb, OVS_CT_ATTR_ZONE, ct_info->zone.id)) nla_put_u16(skb, OVS_CT_ATTR_ZONE, ct_info->zone.id))
return -EMSGSIZE; return -EMSGSIZE;
if (IS_ENABLED(CONFIG_NF_CONNTRACK_MARK) && if (IS_ENABLED(CONFIG_NF_CONNTRACK_MARK) && ct_info->mark.mask &&
nla_put(skb, OVS_CT_ATTR_MARK, sizeof(ct_info->mark), nla_put(skb, OVS_CT_ATTR_MARK, sizeof(ct_info->mark),
&ct_info->mark)) &ct_info->mark))
return -EMSGSIZE; return -EMSGSIZE;
if (IS_ENABLED(CONFIG_NF_CONNTRACK_LABELS) && if (IS_ENABLED(CONFIG_NF_CONNTRACK_LABELS) &&
labels_nonzero(&ct_info->labels.mask) &&
nla_put(skb, OVS_CT_ATTR_LABELS, sizeof(ct_info->labels), nla_put(skb, OVS_CT_ATTR_LABELS, sizeof(ct_info->labels),
&ct_info->labels)) &ct_info->labels))
return -EMSGSIZE; return -EMSGSIZE;

View File

@ -35,12 +35,9 @@ void ovs_ct_fill_key(const struct sk_buff *skb, struct sw_flow_key *key);
int ovs_ct_put_key(const struct sw_flow_key *key, struct sk_buff *skb); int ovs_ct_put_key(const struct sw_flow_key *key, struct sk_buff *skb);
void ovs_ct_free_action(const struct nlattr *a); void ovs_ct_free_action(const struct nlattr *a);
static inline bool ovs_ct_state_supported(u32 state) #define CT_SUPPORTED_MASK (OVS_CS_F_NEW | OVS_CS_F_ESTABLISHED | \
{ OVS_CS_F_RELATED | OVS_CS_F_REPLY_DIR | \
return !(state & ~(OVS_CS_F_NEW | OVS_CS_F_ESTABLISHED | OVS_CS_F_INVALID | OVS_CS_F_TRACKED)
OVS_CS_F_RELATED | OVS_CS_F_REPLY_DIR |
OVS_CS_F_INVALID | OVS_CS_F_TRACKED));
}
#else #else
#include <linux/errno.h> #include <linux/errno.h>
@ -53,11 +50,6 @@ static inline bool ovs_ct_verify(struct net *net, int attr)
return false; return false;
} }
static inline bool ovs_ct_state_supported(u32 state)
{
return false;
}
static inline int ovs_ct_copy_action(struct net *net, const struct nlattr *nla, static inline int ovs_ct_copy_action(struct net *net, const struct nlattr *nla,
const struct sw_flow_key *key, const struct sw_flow_key *key,
struct sw_flow_actions **acts, bool log) struct sw_flow_actions **acts, bool log)
@ -94,5 +86,7 @@ static inline int ovs_ct_put_key(const struct sw_flow_key *key,
} }
static inline void ovs_ct_free_action(const struct nlattr *a) { } static inline void ovs_ct_free_action(const struct nlattr *a) { }
#define CT_SUPPORTED_MASK 0
#endif /* CONFIG_NF_CONNTRACK */ #endif /* CONFIG_NF_CONNTRACK */
#endif /* ovs_conntrack.h */ #endif /* ovs_conntrack.h */

View File

@ -489,9 +489,8 @@ static int queue_userspace_packet(struct datapath *dp, struct sk_buff *skb,
if (upcall_info->egress_tun_info) { if (upcall_info->egress_tun_info) {
nla = nla_nest_start(user_skb, OVS_PACKET_ATTR_EGRESS_TUN_KEY); nla = nla_nest_start(user_skb, OVS_PACKET_ATTR_EGRESS_TUN_KEY);
err = ovs_nla_put_egress_tunnel_key(user_skb, err = ovs_nla_put_tunnel_info(user_skb,
upcall_info->egress_tun_info, upcall_info->egress_tun_info);
upcall_info->egress_tun_opts);
BUG_ON(err); BUG_ON(err);
nla_nest_end(user_skb, nla); nla_nest_end(user_skb, nla);
} }

View File

@ -117,7 +117,6 @@ struct ovs_skb_cb {
*/ */
struct dp_upcall_info { struct dp_upcall_info {
struct ip_tunnel_info *egress_tun_info; struct ip_tunnel_info *egress_tun_info;
const void *egress_tun_opts;
const struct nlattr *userdata; const struct nlattr *userdata;
const struct nlattr *actions; const struct nlattr *actions;
int actions_len; int actions_len;

View File

@ -764,7 +764,7 @@ static int __ip_tun_to_nlattr(struct sk_buff *skb,
if ((output->tun_flags & TUNNEL_OAM) && if ((output->tun_flags & TUNNEL_OAM) &&
nla_put_flag(skb, OVS_TUNNEL_KEY_ATTR_OAM)) nla_put_flag(skb, OVS_TUNNEL_KEY_ATTR_OAM))
return -EMSGSIZE; return -EMSGSIZE;
if (tun_opts) { if (swkey_tun_opts_len) {
if (output->tun_flags & TUNNEL_GENEVE_OPT && if (output->tun_flags & TUNNEL_GENEVE_OPT &&
nla_put(skb, OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS, nla_put(skb, OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS,
swkey_tun_opts_len, tun_opts)) swkey_tun_opts_len, tun_opts))
@ -798,14 +798,13 @@ static int ip_tun_to_nlattr(struct sk_buff *skb,
return 0; return 0;
} }
int ovs_nla_put_egress_tunnel_key(struct sk_buff *skb, int ovs_nla_put_tunnel_info(struct sk_buff *skb,
const struct ip_tunnel_info *egress_tun_info, struct ip_tunnel_info *tun_info)
const void *egress_tun_opts)
{ {
return __ip_tun_to_nlattr(skb, &egress_tun_info->key, return __ip_tun_to_nlattr(skb, &tun_info->key,
egress_tun_opts, ip_tunnel_info_opts(tun_info),
egress_tun_info->options_len, tun_info->options_len,
ip_tunnel_info_af(egress_tun_info)); ip_tunnel_info_af(tun_info));
} }
static int metadata_from_nlattrs(struct net *net, struct sw_flow_match *match, static int metadata_from_nlattrs(struct net *net, struct sw_flow_match *match,
@ -866,7 +865,7 @@ static int metadata_from_nlattrs(struct net *net, struct sw_flow_match *match,
ovs_ct_verify(net, OVS_KEY_ATTR_CT_STATE)) { ovs_ct_verify(net, OVS_KEY_ATTR_CT_STATE)) {
u32 ct_state = nla_get_u32(a[OVS_KEY_ATTR_CT_STATE]); u32 ct_state = nla_get_u32(a[OVS_KEY_ATTR_CT_STATE]);
if (!is_mask && !ovs_ct_state_supported(ct_state)) { if (ct_state & ~CT_SUPPORTED_MASK) {
OVS_NLERR(log, "ct_state flags %08x unsupported", OVS_NLERR(log, "ct_state flags %08x unsupported",
ct_state); ct_state);
return -EINVAL; return -EINVAL;
@ -1149,6 +1148,9 @@ static void nlattr_set(struct nlattr *attr, u8 val,
} else { } else {
memset(nla_data(nla), val, nla_len(nla)); memset(nla_data(nla), val, nla_len(nla));
} }
if (nla_type(nla) == OVS_KEY_ATTR_CT_STATE)
*(u32 *)nla_data(nla) &= CT_SUPPORTED_MASK;
} }
} }
@ -2432,11 +2434,7 @@ static int set_action_to_attr(const struct nlattr *a, struct sk_buff *skb)
if (!start) if (!start)
return -EMSGSIZE; return -EMSGSIZE;
err = ip_tun_to_nlattr(skb, &tun_info->key, err = ovs_nla_put_tunnel_info(skb, tun_info);
tun_info->options_len ?
ip_tunnel_info_opts(tun_info) : NULL,
tun_info->options_len,
ip_tunnel_info_af(tun_info));
if (err) if (err)
return err; return err;
nla_nest_end(skb, start); nla_nest_end(skb, start);

View File

@ -55,9 +55,9 @@ int ovs_nla_put_mask(const struct sw_flow *flow, struct sk_buff *skb);
int ovs_nla_get_match(struct net *, struct sw_flow_match *, int ovs_nla_get_match(struct net *, struct sw_flow_match *,
const struct nlattr *key, const struct nlattr *mask, const struct nlattr *key, const struct nlattr *mask,
bool log); bool log);
int ovs_nla_put_egress_tunnel_key(struct sk_buff *,
const struct ip_tunnel_info *, int ovs_nla_put_tunnel_info(struct sk_buff *skb,
const void *egress_tun_opts); struct ip_tunnel_info *tun_info);
bool ovs_nla_get_ufid(struct sw_flow_id *, const struct nlattr *, bool log); bool ovs_nla_get_ufid(struct sw_flow_id *, const struct nlattr *, bool log);
int ovs_nla_get_identifier(struct sw_flow_id *sfid, const struct nlattr *ufid, int ovs_nla_get_identifier(struct sw_flow_id *sfid, const struct nlattr *ufid,

View File

@ -52,18 +52,6 @@ static int geneve_get_options(const struct vport *vport,
return 0; return 0;
} }
static int geneve_get_egress_tun_info(struct vport *vport, struct sk_buff *skb,
struct dp_upcall_info *upcall)
{
struct geneve_port *geneve_port = geneve_vport(vport);
struct net *net = ovs_dp_get_net(vport->dp);
__be16 dport = htons(geneve_port->port_no);
__be16 sport = udp_flow_src_port(net, skb, 1, USHRT_MAX, true);
return ovs_tunnel_get_egress_info(upcall, ovs_dp_get_net(vport->dp),
skb, IPPROTO_UDP, sport, dport);
}
static struct vport *geneve_tnl_create(const struct vport_parms *parms) static struct vport *geneve_tnl_create(const struct vport_parms *parms)
{ {
struct net *net = ovs_dp_get_net(parms->dp); struct net *net = ovs_dp_get_net(parms->dp);
@ -130,7 +118,6 @@ static struct vport_ops ovs_geneve_vport_ops = {
.get_options = geneve_get_options, .get_options = geneve_get_options,
.send = dev_queue_xmit, .send = dev_queue_xmit,
.owner = THIS_MODULE, .owner = THIS_MODULE,
.get_egress_tun_info = geneve_get_egress_tun_info,
}; };
static int __init ovs_geneve_tnl_init(void) static int __init ovs_geneve_tnl_init(void)

View File

@ -84,18 +84,10 @@ static struct vport *gre_create(const struct vport_parms *parms)
return ovs_netdev_link(vport, parms->name); return ovs_netdev_link(vport, parms->name);
} }
static int gre_get_egress_tun_info(struct vport *vport, struct sk_buff *skb,
struct dp_upcall_info *upcall)
{
return ovs_tunnel_get_egress_info(upcall, ovs_dp_get_net(vport->dp),
skb, IPPROTO_GRE, 0, 0);
}
static struct vport_ops ovs_gre_vport_ops = { static struct vport_ops ovs_gre_vport_ops = {
.type = OVS_VPORT_TYPE_GRE, .type = OVS_VPORT_TYPE_GRE,
.create = gre_create, .create = gre_create,
.send = dev_queue_xmit, .send = dev_queue_xmit,
.get_egress_tun_info = gre_get_egress_tun_info,
.destroy = ovs_netdev_tunnel_destroy, .destroy = ovs_netdev_tunnel_destroy,
.owner = THIS_MODULE, .owner = THIS_MODULE,
}; };

View File

@ -106,12 +106,45 @@ static void internal_dev_destructor(struct net_device *dev)
free_netdev(dev); free_netdev(dev);
} }
static struct rtnl_link_stats64 *
internal_get_stats(struct net_device *dev, struct rtnl_link_stats64 *stats)
{
int i;
memset(stats, 0, sizeof(*stats));
stats->rx_errors = dev->stats.rx_errors;
stats->tx_errors = dev->stats.tx_errors;
stats->tx_dropped = dev->stats.tx_dropped;
stats->rx_dropped = dev->stats.rx_dropped;
for_each_possible_cpu(i) {
const struct pcpu_sw_netstats *percpu_stats;
struct pcpu_sw_netstats local_stats;
unsigned int start;
percpu_stats = per_cpu_ptr(dev->tstats, i);
do {
start = u64_stats_fetch_begin_irq(&percpu_stats->syncp);
local_stats = *percpu_stats;
} while (u64_stats_fetch_retry_irq(&percpu_stats->syncp, start));
stats->rx_bytes += local_stats.rx_bytes;
stats->rx_packets += local_stats.rx_packets;
stats->tx_bytes += local_stats.tx_bytes;
stats->tx_packets += local_stats.tx_packets;
}
return stats;
}
static const struct net_device_ops internal_dev_netdev_ops = { static const struct net_device_ops internal_dev_netdev_ops = {
.ndo_open = internal_dev_open, .ndo_open = internal_dev_open,
.ndo_stop = internal_dev_stop, .ndo_stop = internal_dev_stop,
.ndo_start_xmit = internal_dev_xmit, .ndo_start_xmit = internal_dev_xmit,
.ndo_set_mac_address = eth_mac_addr, .ndo_set_mac_address = eth_mac_addr,
.ndo_change_mtu = internal_dev_change_mtu, .ndo_change_mtu = internal_dev_change_mtu,
.ndo_get_stats64 = internal_get_stats,
}; };
static struct rtnl_link_ops internal_dev_link_ops __read_mostly = { static struct rtnl_link_ops internal_dev_link_ops __read_mostly = {
@ -161,6 +194,11 @@ static struct vport *internal_dev_create(const struct vport_parms *parms)
err = -ENOMEM; err = -ENOMEM;
goto error_free_vport; goto error_free_vport;
} }
vport->dev->tstats = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats);
if (!vport->dev->tstats) {
err = -ENOMEM;
goto error_free_netdev;
}
dev_net_set(vport->dev, ovs_dp_get_net(vport->dp)); dev_net_set(vport->dev, ovs_dp_get_net(vport->dp));
internal_dev = internal_dev_priv(vport->dev); internal_dev = internal_dev_priv(vport->dev);
@ -173,7 +211,7 @@ static struct vport *internal_dev_create(const struct vport_parms *parms)
rtnl_lock(); rtnl_lock();
err = register_netdevice(vport->dev); err = register_netdevice(vport->dev);
if (err) if (err)
goto error_free_netdev; goto error_unlock;
dev_set_promiscuity(vport->dev, 1); dev_set_promiscuity(vport->dev, 1);
rtnl_unlock(); rtnl_unlock();
@ -181,8 +219,10 @@ static struct vport *internal_dev_create(const struct vport_parms *parms)
return vport; return vport;
error_free_netdev: error_unlock:
rtnl_unlock(); rtnl_unlock();
free_percpu(vport->dev->tstats);
error_free_netdev:
free_netdev(vport->dev); free_netdev(vport->dev);
error_free_vport: error_free_vport:
ovs_vport_free(vport); ovs_vport_free(vport);
@ -198,7 +238,7 @@ static void internal_dev_destroy(struct vport *vport)
/* unregister_netdevice() waits for an RCU grace period. */ /* unregister_netdevice() waits for an RCU grace period. */
unregister_netdevice(vport->dev); unregister_netdevice(vport->dev);
free_percpu(vport->dev->tstats);
rtnl_unlock(); rtnl_unlock();
} }

View File

@ -146,32 +146,12 @@ static struct vport *vxlan_create(const struct vport_parms *parms)
return ovs_netdev_link(vport, parms->name); return ovs_netdev_link(vport, parms->name);
} }
static int vxlan_get_egress_tun_info(struct vport *vport, struct sk_buff *skb,
struct dp_upcall_info *upcall)
{
struct vxlan_dev *vxlan = netdev_priv(vport->dev);
struct net *net = ovs_dp_get_net(vport->dp);
unsigned short family = ip_tunnel_info_af(upcall->egress_tun_info);
__be16 dst_port = vxlan_dev_dst_port(vxlan, family);
__be16 src_port;
int port_min;
int port_max;
inet_get_local_port_range(net, &port_min, &port_max);
src_port = udp_flow_src_port(net, skb, 0, 0, true);
return ovs_tunnel_get_egress_info(upcall, net,
skb, IPPROTO_UDP,
src_port, dst_port);
}
static struct vport_ops ovs_vxlan_netdev_vport_ops = { static struct vport_ops ovs_vxlan_netdev_vport_ops = {
.type = OVS_VPORT_TYPE_VXLAN, .type = OVS_VPORT_TYPE_VXLAN,
.create = vxlan_create, .create = vxlan_create,
.destroy = ovs_netdev_tunnel_destroy, .destroy = ovs_netdev_tunnel_destroy,
.get_options = vxlan_get_options, .get_options = vxlan_get_options,
.send = dev_queue_xmit, .send = dev_queue_xmit,
.get_egress_tun_info = vxlan_get_egress_tun_info,
}; };
static int __init ovs_vxlan_tnl_init(void) static int __init ovs_vxlan_tnl_init(void)

View File

@ -480,64 +480,6 @@ void ovs_vport_deferred_free(struct vport *vport)
} }
EXPORT_SYMBOL_GPL(ovs_vport_deferred_free); EXPORT_SYMBOL_GPL(ovs_vport_deferred_free);
int ovs_tunnel_get_egress_info(struct dp_upcall_info *upcall,
struct net *net,
struct sk_buff *skb,
u8 ipproto,
__be16 tp_src,
__be16 tp_dst)
{
struct ip_tunnel_info *egress_tun_info = upcall->egress_tun_info;
const struct ip_tunnel_info *tun_info = skb_tunnel_info(skb);
const struct ip_tunnel_key *tun_key;
u32 skb_mark = skb->mark;
struct rtable *rt;
struct flowi4 fl;
if (unlikely(!tun_info))
return -EINVAL;
if (ip_tunnel_info_af(tun_info) != AF_INET)
return -EINVAL;
tun_key = &tun_info->key;
/* Route lookup to get srouce IP address.
* The process may need to be changed if the corresponding process
* in vports ops changed.
*/
rt = ovs_tunnel_route_lookup(net, tun_key, skb_mark, &fl, ipproto);
if (IS_ERR(rt))
return PTR_ERR(rt);
ip_rt_put(rt);
/* Generate egress_tun_info based on tun_info,
* saddr, tp_src and tp_dst
*/
ip_tunnel_key_init(&egress_tun_info->key,
fl.saddr, tun_key->u.ipv4.dst,
tun_key->tos,
tun_key->ttl,
tp_src, tp_dst,
tun_key->tun_id,
tun_key->tun_flags);
egress_tun_info->options_len = tun_info->options_len;
egress_tun_info->mode = tun_info->mode;
upcall->egress_tun_opts = ip_tunnel_info_opts(egress_tun_info);
return 0;
}
EXPORT_SYMBOL_GPL(ovs_tunnel_get_egress_info);
int ovs_vport_get_egress_tun_info(struct vport *vport, struct sk_buff *skb,
struct dp_upcall_info *upcall)
{
/* get_egress_tun_info() is only implemented on tunnel ports. */
if (unlikely(!vport->ops->get_egress_tun_info))
return -EINVAL;
return vport->ops->get_egress_tun_info(vport, skb, upcall);
}
static unsigned int packet_length(const struct sk_buff *skb) static unsigned int packet_length(const struct sk_buff *skb)
{ {
unsigned int length = skb->len - ETH_HLEN; unsigned int length = skb->len - ETH_HLEN;

View File

@ -27,7 +27,6 @@
#include <linux/skbuff.h> #include <linux/skbuff.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/u64_stats_sync.h> #include <linux/u64_stats_sync.h>
#include <net/route.h>
#include "datapath.h" #include "datapath.h"
@ -53,16 +52,6 @@ int ovs_vport_set_upcall_portids(struct vport *, const struct nlattr *pids);
int ovs_vport_get_upcall_portids(const struct vport *, struct sk_buff *); int ovs_vport_get_upcall_portids(const struct vport *, struct sk_buff *);
u32 ovs_vport_find_upcall_portid(const struct vport *, struct sk_buff *); u32 ovs_vport_find_upcall_portid(const struct vport *, struct sk_buff *);
int ovs_tunnel_get_egress_info(struct dp_upcall_info *upcall,
struct net *net,
struct sk_buff *,
u8 ipproto,
__be16 tp_src,
__be16 tp_dst);
int ovs_vport_get_egress_tun_info(struct vport *vport, struct sk_buff *skb,
struct dp_upcall_info *upcall);
/** /**
* struct vport_portids - array of netlink portids of a vport. * struct vport_portids - array of netlink portids of a vport.
* must be protected by rcu. * must be protected by rcu.
@ -140,8 +129,6 @@ struct vport_parms {
* have any configuration. * have any configuration.
* @send: Send a packet on the device. * @send: Send a packet on the device.
* zero for dropped packets or negative for error. * zero for dropped packets or negative for error.
* @get_egress_tun_info: Get the egress tunnel 5-tuple and other info for
* a packet.
*/ */
struct vport_ops { struct vport_ops {
enum ovs_vport_type type; enum ovs_vport_type type;
@ -154,9 +141,6 @@ struct vport_ops {
int (*get_options)(const struct vport *, struct sk_buff *); int (*get_options)(const struct vport *, struct sk_buff *);
netdev_tx_t (*send) (struct sk_buff *skb); netdev_tx_t (*send) (struct sk_buff *skb);
int (*get_egress_tun_info)(struct vport *, struct sk_buff *,
struct dp_upcall_info *upcall);
struct module *owner; struct module *owner;
struct list_head list; struct list_head list;
}; };

View File

@ -94,10 +94,14 @@ __init int net_sysctl_init(void)
goto out; goto out;
ret = register_pernet_subsys(&sysctl_pernet_ops); ret = register_pernet_subsys(&sysctl_pernet_ops);
if (ret) if (ret)
goto out; goto out1;
register_sysctl_root(&net_sysctl_root); register_sysctl_root(&net_sysctl_root);
out: out:
return ret; return ret;
out1:
unregister_sysctl_table(net_header);
net_header = NULL;
goto out;
} }
struct ctl_table_header *register_net_sysctl(struct net *net, struct ctl_table_header *register_net_sysctl(struct net *net,

View File

@ -42,7 +42,8 @@
#include "core.h" #include "core.h"
#define MAX_PKT_DEFAULT_MCAST 1500 /* bcast link max packet size (fixed) */ #define MAX_PKT_DEFAULT_MCAST 1500 /* bcast link max packet size (fixed) */
#define BCLINK_WIN_DEFAULT 20 /* bcast link window size (default) */ #define BCLINK_WIN_DEFAULT 50 /* bcast link window size (default) */
#define BCLINK_WIN_MIN 32 /* bcast minimum link window size */
const char tipc_bclink_name[] = "broadcast-link"; const char tipc_bclink_name[] = "broadcast-link";
@ -908,9 +909,10 @@ int tipc_bclink_set_queue_limits(struct net *net, u32 limit)
if (!bcl) if (!bcl)
return -ENOPROTOOPT; return -ENOPROTOOPT;
if ((limit < TIPC_MIN_LINK_WIN) || (limit > TIPC_MAX_LINK_WIN)) if (limit < BCLINK_WIN_MIN)
limit = BCLINK_WIN_MIN;
if (limit > TIPC_MAX_LINK_WIN)
return -EINVAL; return -EINVAL;
tipc_bclink_lock(net); tipc_bclink_lock(net);
tipc_link_set_queue_limits(bcl, limit); tipc_link_set_queue_limits(bcl, limit);
tipc_bclink_unlock(net); tipc_bclink_unlock(net);

View File

@ -121,7 +121,7 @@ int tipc_buf_append(struct sk_buff **headbuf, struct sk_buff **buf)
{ {
struct sk_buff *head = *headbuf; struct sk_buff *head = *headbuf;
struct sk_buff *frag = *buf; struct sk_buff *frag = *buf;
struct sk_buff *tail; struct sk_buff *tail = NULL;
struct tipc_msg *msg; struct tipc_msg *msg;
u32 fragid; u32 fragid;
int delta; int delta;
@ -141,9 +141,15 @@ int tipc_buf_append(struct sk_buff **headbuf, struct sk_buff **buf)
if (unlikely(skb_unclone(frag, GFP_ATOMIC))) if (unlikely(skb_unclone(frag, GFP_ATOMIC)))
goto err; goto err;
head = *headbuf = frag; head = *headbuf = frag;
skb_frag_list_init(head);
TIPC_SKB_CB(head)->tail = NULL;
*buf = NULL; *buf = NULL;
TIPC_SKB_CB(head)->tail = NULL;
if (skb_is_nonlinear(head)) {
skb_walk_frags(head, tail) {
TIPC_SKB_CB(head)->tail = tail;
}
} else {
skb_frag_list_init(head);
}
return 0; return 0;
} }

View File

@ -52,6 +52,8 @@
/* IANA assigned UDP port */ /* IANA assigned UDP port */
#define UDP_PORT_DEFAULT 6118 #define UDP_PORT_DEFAULT 6118
#define UDP_MIN_HEADROOM 28
static const struct nla_policy tipc_nl_udp_policy[TIPC_NLA_UDP_MAX + 1] = { static const struct nla_policy tipc_nl_udp_policy[TIPC_NLA_UDP_MAX + 1] = {
[TIPC_NLA_UDP_UNSPEC] = {.type = NLA_UNSPEC}, [TIPC_NLA_UDP_UNSPEC] = {.type = NLA_UNSPEC},
[TIPC_NLA_UDP_LOCAL] = {.type = NLA_BINARY, [TIPC_NLA_UDP_LOCAL] = {.type = NLA_BINARY,
@ -156,6 +158,9 @@ static int tipc_udp_send_msg(struct net *net, struct sk_buff *skb,
struct sk_buff *clone; struct sk_buff *clone;
struct rtable *rt; struct rtable *rt;
if (skb_headroom(skb) < UDP_MIN_HEADROOM)
pskb_expand_head(skb, UDP_MIN_HEADROOM, 0, GFP_ATOMIC);
clone = skb_clone(skb, GFP_ATOMIC); clone = skb_clone(skb, GFP_ATOMIC);
skb_set_inner_protocol(clone, htons(ETH_P_TIPC)); skb_set_inner_protocol(clone, htons(ETH_P_TIPC));
ub = rcu_dereference_rtnl(b->media_ptr); ub = rcu_dereference_rtnl(b->media_ptr);

View File

@ -1948,13 +1948,13 @@ int __vsock_core_init(const struct vsock_transport *t, struct module *owner)
err = misc_register(&vsock_device); err = misc_register(&vsock_device);
if (err) { if (err) {
pr_err("Failed to register misc device\n"); pr_err("Failed to register misc device\n");
return -ENOENT; goto err_reset_transport;
} }
err = proto_register(&vsock_proto, 1); /* we want our slab */ err = proto_register(&vsock_proto, 1); /* we want our slab */
if (err) { if (err) {
pr_err("Cannot register vsock protocol\n"); pr_err("Cannot register vsock protocol\n");
goto err_misc_deregister; goto err_deregister_misc;
} }
err = sock_register(&vsock_family_ops); err = sock_register(&vsock_family_ops);
@ -1969,8 +1969,9 @@ int __vsock_core_init(const struct vsock_transport *t, struct module *owner)
err_unregister_proto: err_unregister_proto:
proto_unregister(&vsock_proto); proto_unregister(&vsock_proto);
err_misc_deregister: err_deregister_misc:
misc_deregister(&vsock_device); misc_deregister(&vsock_device);
err_reset_transport:
transport = NULL; transport = NULL;
err_busy: err_busy:
mutex_unlock(&vsock_register_mutex); mutex_unlock(&vsock_register_mutex);

View File

@ -40,13 +40,11 @@
static int vmci_transport_recv_dgram_cb(void *data, struct vmci_datagram *dg); static int vmci_transport_recv_dgram_cb(void *data, struct vmci_datagram *dg);
static int vmci_transport_recv_stream_cb(void *data, struct vmci_datagram *dg); static int vmci_transport_recv_stream_cb(void *data, struct vmci_datagram *dg);
static void vmci_transport_peer_attach_cb(u32 sub_id,
const struct vmci_event_data *ed,
void *client_data);
static void vmci_transport_peer_detach_cb(u32 sub_id, static void vmci_transport_peer_detach_cb(u32 sub_id,
const struct vmci_event_data *ed, const struct vmci_event_data *ed,
void *client_data); void *client_data);
static void vmci_transport_recv_pkt_work(struct work_struct *work); static void vmci_transport_recv_pkt_work(struct work_struct *work);
static void vmci_transport_cleanup(struct work_struct *work);
static int vmci_transport_recv_listen(struct sock *sk, static int vmci_transport_recv_listen(struct sock *sk,
struct vmci_transport_packet *pkt); struct vmci_transport_packet *pkt);
static int vmci_transport_recv_connecting_server( static int vmci_transport_recv_connecting_server(
@ -75,6 +73,10 @@ struct vmci_transport_recv_pkt_info {
struct vmci_transport_packet pkt; struct vmci_transport_packet pkt;
}; };
static LIST_HEAD(vmci_transport_cleanup_list);
static DEFINE_SPINLOCK(vmci_transport_cleanup_lock);
static DECLARE_WORK(vmci_transport_cleanup_work, vmci_transport_cleanup);
static struct vmci_handle vmci_transport_stream_handle = { VMCI_INVALID_ID, static struct vmci_handle vmci_transport_stream_handle = { VMCI_INVALID_ID,
VMCI_INVALID_ID }; VMCI_INVALID_ID };
static u32 vmci_transport_qp_resumed_sub_id = VMCI_INVALID_ID; static u32 vmci_transport_qp_resumed_sub_id = VMCI_INVALID_ID;
@ -791,44 +793,6 @@ out:
return err; return err;
} }
static void vmci_transport_peer_attach_cb(u32 sub_id,
const struct vmci_event_data *e_data,
void *client_data)
{
struct sock *sk = client_data;
const struct vmci_event_payload_qp *e_payload;
struct vsock_sock *vsk;
e_payload = vmci_event_data_const_payload(e_data);
vsk = vsock_sk(sk);
/* We don't ask for delayed CBs when we subscribe to this event (we
* pass 0 as flags to vmci_event_subscribe()). VMCI makes no
* guarantees in that case about what context we might be running in,
* so it could be BH or process, blockable or non-blockable. So we
* need to account for all possible contexts here.
*/
local_bh_disable();
bh_lock_sock(sk);
/* XXX This is lame, we should provide a way to lookup sockets by
* qp_handle.
*/
if (vmci_handle_is_equal(vmci_trans(vsk)->qp_handle,
e_payload->handle)) {
/* XXX This doesn't do anything, but in the future we may want
* to set a flag here to verify the attach really did occur and
* we weren't just sent a datagram claiming it was.
*/
goto out;
}
out:
bh_unlock_sock(sk);
local_bh_enable();
}
static void vmci_transport_handle_detach(struct sock *sk) static void vmci_transport_handle_detach(struct sock *sk)
{ {
struct vsock_sock *vsk; struct vsock_sock *vsk;
@ -871,28 +835,38 @@ static void vmci_transport_peer_detach_cb(u32 sub_id,
const struct vmci_event_data *e_data, const struct vmci_event_data *e_data,
void *client_data) void *client_data)
{ {
struct sock *sk = client_data; struct vmci_transport *trans = client_data;
const struct vmci_event_payload_qp *e_payload; const struct vmci_event_payload_qp *e_payload;
struct vsock_sock *vsk;
e_payload = vmci_event_data_const_payload(e_data); e_payload = vmci_event_data_const_payload(e_data);
vsk = vsock_sk(sk);
if (vmci_handle_is_invalid(e_payload->handle))
return;
/* Same rules for locking as for peer_attach_cb(). */
local_bh_disable();
bh_lock_sock(sk);
/* XXX This is lame, we should provide a way to lookup sockets by /* XXX This is lame, we should provide a way to lookup sockets by
* qp_handle. * qp_handle.
*/ */
if (vmci_handle_is_equal(vmci_trans(vsk)->qp_handle, if (vmci_handle_is_invalid(e_payload->handle) ||
e_payload->handle)) vmci_handle_is_equal(trans->qp_handle, e_payload->handle))
vmci_transport_handle_detach(sk); return;
bh_unlock_sock(sk); /* We don't ask for delayed CBs when we subscribe to this event (we
local_bh_enable(); * pass 0 as flags to vmci_event_subscribe()). VMCI makes no
* guarantees in that case about what context we might be running in,
* so it could be BH or process, blockable or non-blockable. So we
* need to account for all possible contexts here.
*/
spin_lock_bh(&trans->lock);
if (!trans->sk)
goto out;
/* Apart from here, trans->lock is only grabbed as part of sk destruct,
* where trans->sk isn't locked.
*/
bh_lock_sock(trans->sk);
vmci_transport_handle_detach(trans->sk);
bh_unlock_sock(trans->sk);
out:
spin_unlock_bh(&trans->lock);
} }
static void vmci_transport_qp_resumed_cb(u32 sub_id, static void vmci_transport_qp_resumed_cb(u32 sub_id,
@ -1181,7 +1155,7 @@ vmci_transport_recv_connecting_server(struct sock *listener,
*/ */
err = vmci_event_subscribe(VMCI_EVENT_QP_PEER_DETACH, err = vmci_event_subscribe(VMCI_EVENT_QP_PEER_DETACH,
vmci_transport_peer_detach_cb, vmci_transport_peer_detach_cb,
pending, &detach_sub_id); vmci_trans(vpending), &detach_sub_id);
if (err < VMCI_SUCCESS) { if (err < VMCI_SUCCESS) {
vmci_transport_send_reset(pending, pkt); vmci_transport_send_reset(pending, pkt);
err = vmci_transport_error_to_vsock_error(err); err = vmci_transport_error_to_vsock_error(err);
@ -1321,7 +1295,6 @@ vmci_transport_recv_connecting_client(struct sock *sk,
|| vmci_trans(vsk)->qpair || vmci_trans(vsk)->qpair
|| vmci_trans(vsk)->produce_size != 0 || vmci_trans(vsk)->produce_size != 0
|| vmci_trans(vsk)->consume_size != 0 || vmci_trans(vsk)->consume_size != 0
|| vmci_trans(vsk)->attach_sub_id != VMCI_INVALID_ID
|| vmci_trans(vsk)->detach_sub_id != VMCI_INVALID_ID) { || vmci_trans(vsk)->detach_sub_id != VMCI_INVALID_ID) {
skerr = EPROTO; skerr = EPROTO;
err = -EINVAL; err = -EINVAL;
@ -1389,7 +1362,6 @@ static int vmci_transport_recv_connecting_client_negotiate(
struct vsock_sock *vsk; struct vsock_sock *vsk;
struct vmci_handle handle; struct vmci_handle handle;
struct vmci_qp *qpair; struct vmci_qp *qpair;
u32 attach_sub_id;
u32 detach_sub_id; u32 detach_sub_id;
bool is_local; bool is_local;
u32 flags; u32 flags;
@ -1399,7 +1371,6 @@ static int vmci_transport_recv_connecting_client_negotiate(
vsk = vsock_sk(sk); vsk = vsock_sk(sk);
handle = VMCI_INVALID_HANDLE; handle = VMCI_INVALID_HANDLE;
attach_sub_id = VMCI_INVALID_ID;
detach_sub_id = VMCI_INVALID_ID; detach_sub_id = VMCI_INVALID_ID;
/* If we have gotten here then we should be past the point where old /* If we have gotten here then we should be past the point where old
@ -1444,23 +1415,15 @@ static int vmci_transport_recv_connecting_client_negotiate(
goto destroy; goto destroy;
} }
/* Subscribe to attach and detach events first. /* Subscribe to detach events first.
* *
* XXX We attach once for each queue pair created for now so it is easy * XXX We attach once for each queue pair created for now so it is easy
* to find the socket (it's provided), but later we should only * to find the socket (it's provided), but later we should only
* subscribe once and add a way to lookup sockets by queue pair handle. * subscribe once and add a way to lookup sockets by queue pair handle.
*/ */
err = vmci_event_subscribe(VMCI_EVENT_QP_PEER_ATTACH,
vmci_transport_peer_attach_cb,
sk, &attach_sub_id);
if (err < VMCI_SUCCESS) {
err = vmci_transport_error_to_vsock_error(err);
goto destroy;
}
err = vmci_event_subscribe(VMCI_EVENT_QP_PEER_DETACH, err = vmci_event_subscribe(VMCI_EVENT_QP_PEER_DETACH,
vmci_transport_peer_detach_cb, vmci_transport_peer_detach_cb,
sk, &detach_sub_id); vmci_trans(vsk), &detach_sub_id);
if (err < VMCI_SUCCESS) { if (err < VMCI_SUCCESS) {
err = vmci_transport_error_to_vsock_error(err); err = vmci_transport_error_to_vsock_error(err);
goto destroy; goto destroy;
@ -1496,7 +1459,6 @@ static int vmci_transport_recv_connecting_client_negotiate(
vmci_trans(vsk)->produce_size = vmci_trans(vsk)->consume_size = vmci_trans(vsk)->produce_size = vmci_trans(vsk)->consume_size =
pkt->u.size; pkt->u.size;
vmci_trans(vsk)->attach_sub_id = attach_sub_id;
vmci_trans(vsk)->detach_sub_id = detach_sub_id; vmci_trans(vsk)->detach_sub_id = detach_sub_id;
vmci_trans(vsk)->notify_ops->process_negotiate(sk); vmci_trans(vsk)->notify_ops->process_negotiate(sk);
@ -1504,9 +1466,6 @@ static int vmci_transport_recv_connecting_client_negotiate(
return 0; return 0;
destroy: destroy:
if (attach_sub_id != VMCI_INVALID_ID)
vmci_event_unsubscribe(attach_sub_id);
if (detach_sub_id != VMCI_INVALID_ID) if (detach_sub_id != VMCI_INVALID_ID)
vmci_event_unsubscribe(detach_sub_id); vmci_event_unsubscribe(detach_sub_id);
@ -1607,9 +1566,11 @@ static int vmci_transport_socket_init(struct vsock_sock *vsk,
vmci_trans(vsk)->qp_handle = VMCI_INVALID_HANDLE; vmci_trans(vsk)->qp_handle = VMCI_INVALID_HANDLE;
vmci_trans(vsk)->qpair = NULL; vmci_trans(vsk)->qpair = NULL;
vmci_trans(vsk)->produce_size = vmci_trans(vsk)->consume_size = 0; vmci_trans(vsk)->produce_size = vmci_trans(vsk)->consume_size = 0;
vmci_trans(vsk)->attach_sub_id = vmci_trans(vsk)->detach_sub_id = vmci_trans(vsk)->detach_sub_id = VMCI_INVALID_ID;
VMCI_INVALID_ID;
vmci_trans(vsk)->notify_ops = NULL; vmci_trans(vsk)->notify_ops = NULL;
INIT_LIST_HEAD(&vmci_trans(vsk)->elem);
vmci_trans(vsk)->sk = &vsk->sk;
spin_lock_init(&vmci_trans(vsk)->lock);
if (psk) { if (psk) {
vmci_trans(vsk)->queue_pair_size = vmci_trans(vsk)->queue_pair_size =
vmci_trans(psk)->queue_pair_size; vmci_trans(psk)->queue_pair_size;
@ -1629,29 +1590,57 @@ static int vmci_transport_socket_init(struct vsock_sock *vsk,
return 0; return 0;
} }
static void vmci_transport_free_resources(struct list_head *transport_list)
{
while (!list_empty(transport_list)) {
struct vmci_transport *transport =
list_first_entry(transport_list, struct vmci_transport,
elem);
list_del(&transport->elem);
if (transport->detach_sub_id != VMCI_INVALID_ID) {
vmci_event_unsubscribe(transport->detach_sub_id);
transport->detach_sub_id = VMCI_INVALID_ID;
}
if (!vmci_handle_is_invalid(transport->qp_handle)) {
vmci_qpair_detach(&transport->qpair);
transport->qp_handle = VMCI_INVALID_HANDLE;
transport->produce_size = 0;
transport->consume_size = 0;
}
kfree(transport);
}
}
static void vmci_transport_cleanup(struct work_struct *work)
{
LIST_HEAD(pending);
spin_lock_bh(&vmci_transport_cleanup_lock);
list_replace_init(&vmci_transport_cleanup_list, &pending);
spin_unlock_bh(&vmci_transport_cleanup_lock);
vmci_transport_free_resources(&pending);
}
static void vmci_transport_destruct(struct vsock_sock *vsk) static void vmci_transport_destruct(struct vsock_sock *vsk)
{ {
if (vmci_trans(vsk)->attach_sub_id != VMCI_INVALID_ID) { /* Ensure that the detach callback doesn't use the sk/vsk
vmci_event_unsubscribe(vmci_trans(vsk)->attach_sub_id); * we are about to destruct.
vmci_trans(vsk)->attach_sub_id = VMCI_INVALID_ID; */
} spin_lock_bh(&vmci_trans(vsk)->lock);
vmci_trans(vsk)->sk = NULL;
if (vmci_trans(vsk)->detach_sub_id != VMCI_INVALID_ID) { spin_unlock_bh(&vmci_trans(vsk)->lock);
vmci_event_unsubscribe(vmci_trans(vsk)->detach_sub_id);
vmci_trans(vsk)->detach_sub_id = VMCI_INVALID_ID;
}
if (!vmci_handle_is_invalid(vmci_trans(vsk)->qp_handle)) {
vmci_qpair_detach(&vmci_trans(vsk)->qpair);
vmci_trans(vsk)->qp_handle = VMCI_INVALID_HANDLE;
vmci_trans(vsk)->produce_size = 0;
vmci_trans(vsk)->consume_size = 0;
}
if (vmci_trans(vsk)->notify_ops) if (vmci_trans(vsk)->notify_ops)
vmci_trans(vsk)->notify_ops->socket_destruct(vsk); vmci_trans(vsk)->notify_ops->socket_destruct(vsk);
kfree(vsk->trans); spin_lock_bh(&vmci_transport_cleanup_lock);
list_add(&vmci_trans(vsk)->elem, &vmci_transport_cleanup_list);
spin_unlock_bh(&vmci_transport_cleanup_lock);
schedule_work(&vmci_transport_cleanup_work);
vsk->trans = NULL; vsk->trans = NULL;
} }
@ -2146,6 +2135,9 @@ module_init(vmci_transport_init);
static void __exit vmci_transport_exit(void) static void __exit vmci_transport_exit(void)
{ {
cancel_work_sync(&vmci_transport_cleanup_work);
vmci_transport_free_resources(&vmci_transport_cleanup_list);
if (!vmci_handle_is_invalid(vmci_transport_stream_handle)) { if (!vmci_handle_is_invalid(vmci_transport_stream_handle)) {
if (vmci_datagram_destroy_handle( if (vmci_datagram_destroy_handle(
vmci_transport_stream_handle) != VMCI_SUCCESS) vmci_transport_stream_handle) != VMCI_SUCCESS)
@ -2164,6 +2156,7 @@ module_exit(vmci_transport_exit);
MODULE_AUTHOR("VMware, Inc."); MODULE_AUTHOR("VMware, Inc.");
MODULE_DESCRIPTION("VMCI transport for Virtual Sockets"); MODULE_DESCRIPTION("VMCI transport for Virtual Sockets");
MODULE_VERSION("1.0.2.0-k");
MODULE_LICENSE("GPL v2"); MODULE_LICENSE("GPL v2");
MODULE_ALIAS("vmware_vsock"); MODULE_ALIAS("vmware_vsock");
MODULE_ALIAS_NETPROTO(PF_VSOCK); MODULE_ALIAS_NETPROTO(PF_VSOCK);

View File

@ -119,10 +119,12 @@ struct vmci_transport {
u64 queue_pair_size; u64 queue_pair_size;
u64 queue_pair_min_size; u64 queue_pair_min_size;
u64 queue_pair_max_size; u64 queue_pair_max_size;
u32 attach_sub_id;
u32 detach_sub_id; u32 detach_sub_id;
union vmci_transport_notify notify; union vmci_transport_notify notify;
struct vmci_transport_notify_ops *notify_ops; struct vmci_transport_notify_ops *notify_ops;
struct list_head elem;
struct sock *sk;
spinlock_t lock; /* protects sk. */
}; };
int vmci_transport_register(void); int vmci_transport_register(void);

View File

@ -1928,8 +1928,10 @@ static int xfrm_new_ae(struct sk_buff *skb, struct nlmsghdr *nlh,
struct nlattr *rp = attrs[XFRMA_REPLAY_VAL]; struct nlattr *rp = attrs[XFRMA_REPLAY_VAL];
struct nlattr *re = attrs[XFRMA_REPLAY_ESN_VAL]; struct nlattr *re = attrs[XFRMA_REPLAY_ESN_VAL];
struct nlattr *lt = attrs[XFRMA_LTIME_VAL]; struct nlattr *lt = attrs[XFRMA_LTIME_VAL];
struct nlattr *et = attrs[XFRMA_ETIMER_THRESH];
struct nlattr *rt = attrs[XFRMA_REPLAY_THRESH];
if (!lt && !rp && !re) if (!lt && !rp && !re && !et && !rt)
return err; return err;
/* pedantic mode - thou shalt sayeth replaceth */ /* pedantic mode - thou shalt sayeth replaceth */