diff options
-rw-r--r-- | Documentation/networking/ipvlan.txt | 42 | ||||
-rw-r--r-- | drivers/net/ipvlan/ipvlan.h | 31 | ||||
-rw-r--r-- | drivers/net/ipvlan/ipvlan_core.c | 24 | ||||
-rw-r--r-- | drivers/net/ipvlan/ipvlan_main.c | 47 | ||||
-rw-r--r-- | include/uapi/linux/if_link.h | 4 |
5 files changed, 136 insertions, 12 deletions
diff --git a/Documentation/networking/ipvlan.txt b/Documentation/networking/ipvlan.txt index 1fe42a874aae..812ef003e0a8 100644 --- a/Documentation/networking/ipvlan.txt +++ b/Documentation/networking/ipvlan.txt | |||
@@ -22,9 +22,21 @@ The driver can be built into the kernel (CONFIG_IPVLAN=y) or as a module | |||
22 | There are no module parameters for this driver and it can be configured | 22 | There are no module parameters for this driver and it can be configured |
23 | using IProute2/ip utility. | 23 | using IProute2/ip utility. |
24 | 24 | ||
25 | ip link add link <master-dev> name <slave-dev> type ipvlan mode { l2 | l3 | l3s } | 25 | ip link add link <master> name <slave> type ipvlan [ mode MODE ] [ FLAGS ] |
26 | 26 | where | |
27 | e.g. ip link add link eth0 name ipvl0 type ipvlan mode l2 | 27 | MODE: l3 (default) | l3s | l2 |
28 | FLAGS: bridge (default) | private | vepa | ||
29 | |||
30 | e.g. | ||
31 | (a) Following will create IPvlan link with eth0 as master in | ||
32 | L3 bridge mode | ||
33 | bash# ip link add link eth0 name ipvl0 type ipvlan | ||
34 | (b) This command will create IPvlan link in L2 bridge mode. | ||
35 | bash# ip link add link eth0 name ipvl0 type ipvlan mode l2 bridge | ||
36 | (c) This command will create an IPvlan device in L2 private mode. | ||
37 | bash# ip link add link eth0 name ipvlan type ipvlan mode l2 private | ||
38 | (d) This command will create an IPvlan device in L2 vepa mode. | ||
39 | bash# ip link add link eth0 name ipvlan type ipvlan mode l2 vepa | ||
28 | 40 | ||
29 | 41 | ||
30 | 4. Operating modes: | 42 | 4. Operating modes: |
@@ -54,7 +66,29 @@ works in this mode and hence it is L3-symmetric (L3s). This will have slightly l | |||
54 | performance but that shouldn't matter since you are choosing this mode over plain-L3 | 66 | performance but that shouldn't matter since you are choosing this mode over plain-L3 |
55 | mode to make conn-tracking work. | 67 | mode to make conn-tracking work. |
56 | 68 | ||
57 | 5. What to choose (macvlan vs. ipvlan)? | 69 | 5. Mode flags: |
70 | At this time following mode flags are available | ||
71 | |||
72 | 5.1 bridge: | ||
73 | This is the default option. To configure the IPvlan port in this mode, | ||
74 | user can choose to either add this option on the command-line or don't specify | ||
75 | anything. This is the traditional mode where slaves can cross-talk among | ||
76 | themseleves apart from talking through the master device. | ||
77 | |||
78 | 5.2 private: | ||
79 | If this option is added to the command-line, the port is set in private | ||
80 | mode. i.e. port wont allow cross communication between slaves. | ||
81 | |||
82 | 5.3 vepa: | ||
83 | If this is added to the command-line, the port is set in VEPA mode. | ||
84 | i.e. port will offload switching functionality to the external entity as | ||
85 | described in 802.1Qbg | ||
86 | Note: VEPA mode in IPvlan has limitations. IPvlan uses the mac-address of the | ||
87 | master-device, so the packets which are emitted in this mode for the adjacent | ||
88 | neighbor will have source and destination mac same. This will make the switch / | ||
89 | router send the redirect message. | ||
90 | |||
91 | 6. What to choose (macvlan vs. ipvlan)? | ||
58 | These two devices are very similar in many regards and the specific use | 92 | These two devices are very similar in many regards and the specific use |
59 | case could very well define which device to choose. if one of the following | 93 | case could very well define which device to choose. if one of the following |
60 | situations defines your use case then you can choose to use ipvlan - | 94 | situations defines your use case then you can choose to use ipvlan - |
diff --git a/drivers/net/ipvlan/ipvlan.h b/drivers/net/ipvlan/ipvlan.h index ba8173a0b62e..5166575a164d 100644 --- a/drivers/net/ipvlan/ipvlan.h +++ b/drivers/net/ipvlan/ipvlan.h | |||
@@ -96,6 +96,7 @@ struct ipvl_port { | |||
96 | struct hlist_head hlhead[IPVLAN_HASH_SIZE]; | 96 | struct hlist_head hlhead[IPVLAN_HASH_SIZE]; |
97 | struct list_head ipvlans; | 97 | struct list_head ipvlans; |
98 | u16 mode; | 98 | u16 mode; |
99 | u16 flags; | ||
99 | u16 dev_id_start; | 100 | u16 dev_id_start; |
100 | struct work_struct wq; | 101 | struct work_struct wq; |
101 | struct sk_buff_head backlog; | 102 | struct sk_buff_head backlog; |
@@ -123,6 +124,36 @@ static inline struct ipvl_port *ipvlan_port_get_rtnl(const struct net_device *d) | |||
123 | return rtnl_dereference(d->rx_handler_data); | 124 | return rtnl_dereference(d->rx_handler_data); |
124 | } | 125 | } |
125 | 126 | ||
127 | static inline bool ipvlan_is_private(const struct ipvl_port *port) | ||
128 | { | ||
129 | return !!(port->flags & IPVLAN_F_PRIVATE); | ||
130 | } | ||
131 | |||
132 | static inline void ipvlan_mark_private(struct ipvl_port *port) | ||
133 | { | ||
134 | port->flags |= IPVLAN_F_PRIVATE; | ||
135 | } | ||
136 | |||
137 | static inline void ipvlan_clear_private(struct ipvl_port *port) | ||
138 | { | ||
139 | port->flags &= ~IPVLAN_F_PRIVATE; | ||
140 | } | ||
141 | |||
142 | static inline bool ipvlan_is_vepa(const struct ipvl_port *port) | ||
143 | { | ||
144 | return !!(port->flags & IPVLAN_F_VEPA); | ||
145 | } | ||
146 | |||
147 | static inline void ipvlan_mark_vepa(struct ipvl_port *port) | ||
148 | { | ||
149 | port->flags |= IPVLAN_F_VEPA; | ||
150 | } | ||
151 | |||
152 | static inline void ipvlan_clear_vepa(struct ipvl_port *port) | ||
153 | { | ||
154 | port->flags &= ~IPVLAN_F_VEPA; | ||
155 | } | ||
156 | |||
126 | void ipvlan_init_secret(void); | 157 | void ipvlan_init_secret(void); |
127 | unsigned int ipvlan_mac_hash(const unsigned char *addr); | 158 | unsigned int ipvlan_mac_hash(const unsigned char *addr); |
128 | rx_handler_result_t ipvlan_handle_frame(struct sk_buff **pskb); | 159 | rx_handler_result_t ipvlan_handle_frame(struct sk_buff **pskb); |
diff --git a/drivers/net/ipvlan/ipvlan_core.c b/drivers/net/ipvlan/ipvlan_core.c index 1f3295e274d0..034ae4c57196 100644 --- a/drivers/net/ipvlan/ipvlan_core.c +++ b/drivers/net/ipvlan/ipvlan_core.c | |||
@@ -514,10 +514,16 @@ static int ipvlan_xmit_mode_l3(struct sk_buff *skb, struct net_device *dev) | |||
514 | if (!lyr3h) | 514 | if (!lyr3h) |
515 | goto out; | 515 | goto out; |
516 | 516 | ||
517 | addr = ipvlan_addr_lookup(ipvlan->port, lyr3h, addr_type, true); | 517 | if (!ipvlan_is_vepa(ipvlan->port)) { |
518 | if (addr) | 518 | addr = ipvlan_addr_lookup(ipvlan->port, lyr3h, addr_type, true); |
519 | return ipvlan_rcv_frame(addr, &skb, true); | 519 | if (addr) { |
520 | 520 | if (ipvlan_is_private(ipvlan->port)) { | |
521 | consume_skb(skb); | ||
522 | return NET_XMIT_DROP; | ||
523 | } | ||
524 | return ipvlan_rcv_frame(addr, &skb, true); | ||
525 | } | ||
526 | } | ||
521 | out: | 527 | out: |
522 | ipvlan_skb_crossing_ns(skb, ipvlan->phy_dev); | 528 | ipvlan_skb_crossing_ns(skb, ipvlan->phy_dev); |
523 | return ipvlan_process_outbound(skb); | 529 | return ipvlan_process_outbound(skb); |
@@ -531,12 +537,18 @@ static int ipvlan_xmit_mode_l2(struct sk_buff *skb, struct net_device *dev) | |||
531 | void *lyr3h; | 537 | void *lyr3h; |
532 | int addr_type; | 538 | int addr_type; |
533 | 539 | ||
534 | if (ether_addr_equal(eth->h_dest, eth->h_source)) { | 540 | if (!ipvlan_is_vepa(ipvlan->port) && |
541 | ether_addr_equal(eth->h_dest, eth->h_source)) { | ||
535 | lyr3h = ipvlan_get_L3_hdr(skb, &addr_type); | 542 | lyr3h = ipvlan_get_L3_hdr(skb, &addr_type); |
536 | if (lyr3h) { | 543 | if (lyr3h) { |
537 | addr = ipvlan_addr_lookup(ipvlan->port, lyr3h, addr_type, true); | 544 | addr = ipvlan_addr_lookup(ipvlan->port, lyr3h, addr_type, true); |
538 | if (addr) | 545 | if (addr) { |
546 | if (ipvlan_is_private(ipvlan->port)) { | ||
547 | consume_skb(skb); | ||
548 | return NET_XMIT_DROP; | ||
549 | } | ||
539 | return ipvlan_rcv_frame(addr, &skb, true); | 550 | return ipvlan_rcv_frame(addr, &skb, true); |
551 | } | ||
540 | } | 552 | } |
541 | skb = skb_share_check(skb, GFP_ATOMIC); | 553 | skb = skb_share_check(skb, GFP_ATOMIC); |
542 | if (!skb) | 554 | if (!skb) |
diff --git a/drivers/net/ipvlan/ipvlan_main.c b/drivers/net/ipvlan/ipvlan_main.c index f0ab55df57f1..a266aa435d4d 100644 --- a/drivers/net/ipvlan/ipvlan_main.c +++ b/drivers/net/ipvlan/ipvlan_main.c | |||
@@ -462,11 +462,29 @@ static int ipvlan_nl_changelink(struct net_device *dev, | |||
462 | struct ipvl_port *port = ipvlan_port_get_rtnl(ipvlan->phy_dev); | 462 | struct ipvl_port *port = ipvlan_port_get_rtnl(ipvlan->phy_dev); |
463 | int err = 0; | 463 | int err = 0; |
464 | 464 | ||
465 | if (data && data[IFLA_IPVLAN_MODE]) { | 465 | if (!data) |
466 | return 0; | ||
467 | |||
468 | if (data[IFLA_IPVLAN_MODE]) { | ||
466 | u16 nmode = nla_get_u16(data[IFLA_IPVLAN_MODE]); | 469 | u16 nmode = nla_get_u16(data[IFLA_IPVLAN_MODE]); |
467 | 470 | ||
468 | err = ipvlan_set_port_mode(port, nmode); | 471 | err = ipvlan_set_port_mode(port, nmode); |
469 | } | 472 | } |
473 | |||
474 | if (!err && data[IFLA_IPVLAN_FLAGS]) { | ||
475 | u16 flags = nla_get_u16(data[IFLA_IPVLAN_FLAGS]); | ||
476 | |||
477 | if (flags & IPVLAN_F_PRIVATE) | ||
478 | ipvlan_mark_private(port); | ||
479 | else | ||
480 | ipvlan_clear_private(port); | ||
481 | |||
482 | if (flags & IPVLAN_F_VEPA) | ||
483 | ipvlan_mark_vepa(port); | ||
484 | else | ||
485 | ipvlan_clear_vepa(port); | ||
486 | } | ||
487 | |||
470 | return err; | 488 | return err; |
471 | } | 489 | } |
472 | 490 | ||
@@ -474,18 +492,34 @@ static size_t ipvlan_nl_getsize(const struct net_device *dev) | |||
474 | { | 492 | { |
475 | return (0 | 493 | return (0 |
476 | + nla_total_size(2) /* IFLA_IPVLAN_MODE */ | 494 | + nla_total_size(2) /* IFLA_IPVLAN_MODE */ |
495 | + nla_total_size(2) /* IFLA_IPVLAN_FLAGS */ | ||
477 | ); | 496 | ); |
478 | } | 497 | } |
479 | 498 | ||
480 | static int ipvlan_nl_validate(struct nlattr *tb[], struct nlattr *data[], | 499 | static int ipvlan_nl_validate(struct nlattr *tb[], struct nlattr *data[], |
481 | struct netlink_ext_ack *extack) | 500 | struct netlink_ext_ack *extack) |
482 | { | 501 | { |
483 | if (data && data[IFLA_IPVLAN_MODE]) { | 502 | if (!data) |
503 | return 0; | ||
504 | |||
505 | if (data[IFLA_IPVLAN_MODE]) { | ||
484 | u16 mode = nla_get_u16(data[IFLA_IPVLAN_MODE]); | 506 | u16 mode = nla_get_u16(data[IFLA_IPVLAN_MODE]); |
485 | 507 | ||
486 | if (mode < IPVLAN_MODE_L2 || mode >= IPVLAN_MODE_MAX) | 508 | if (mode < IPVLAN_MODE_L2 || mode >= IPVLAN_MODE_MAX) |
487 | return -EINVAL; | 509 | return -EINVAL; |
488 | } | 510 | } |
511 | if (data[IFLA_IPVLAN_FLAGS]) { | ||
512 | u16 flags = nla_get_u16(data[IFLA_IPVLAN_FLAGS]); | ||
513 | |||
514 | /* Only two bits are used at this moment. */ | ||
515 | if (flags & ~(IPVLAN_F_PRIVATE | IPVLAN_F_VEPA)) | ||
516 | return -EINVAL; | ||
517 | /* Also both flags can't be active at the same time. */ | ||
518 | if ((flags & (IPVLAN_F_PRIVATE | IPVLAN_F_VEPA)) == | ||
519 | (IPVLAN_F_PRIVATE | IPVLAN_F_VEPA)) | ||
520 | return -EINVAL; | ||
521 | } | ||
522 | |||
489 | return 0; | 523 | return 0; |
490 | } | 524 | } |
491 | 525 | ||
@@ -502,6 +536,8 @@ static int ipvlan_nl_fillinfo(struct sk_buff *skb, | |||
502 | ret = -EMSGSIZE; | 536 | ret = -EMSGSIZE; |
503 | if (nla_put_u16(skb, IFLA_IPVLAN_MODE, port->mode)) | 537 | if (nla_put_u16(skb, IFLA_IPVLAN_MODE, port->mode)) |
504 | goto err; | 538 | goto err; |
539 | if (nla_put_u16(skb, IFLA_IPVLAN_FLAGS, port->flags)) | ||
540 | goto err; | ||
505 | 541 | ||
506 | return 0; | 542 | return 0; |
507 | 543 | ||
@@ -549,6 +585,12 @@ int ipvlan_link_new(struct net *src_net, struct net_device *dev, | |||
549 | ipvlan_adjust_mtu(ipvlan, phy_dev); | 585 | ipvlan_adjust_mtu(ipvlan, phy_dev); |
550 | INIT_LIST_HEAD(&ipvlan->addrs); | 586 | INIT_LIST_HEAD(&ipvlan->addrs); |
551 | 587 | ||
588 | /* Flags are per port and latest update overrides. User has | ||
589 | * to be consistent in setting it just like the mode attribute. | ||
590 | */ | ||
591 | if (data && data[IFLA_IPVLAN_FLAGS]) | ||
592 | ipvlan->port->flags = nla_get_u16(data[IFLA_IPVLAN_FLAGS]); | ||
593 | |||
552 | /* If the port-id base is at the MAX value, then wrap it around and | 594 | /* If the port-id base is at the MAX value, then wrap it around and |
553 | * begin from 0x1 again. This may be due to a busy system where lots | 595 | * begin from 0x1 again. This may be due to a busy system where lots |
554 | * of slaves are getting created and deleted. | 596 | * of slaves are getting created and deleted. |
@@ -644,6 +686,7 @@ EXPORT_SYMBOL_GPL(ipvlan_link_setup); | |||
644 | static const struct nla_policy ipvlan_nl_policy[IFLA_IPVLAN_MAX + 1] = | 686 | static const struct nla_policy ipvlan_nl_policy[IFLA_IPVLAN_MAX + 1] = |
645 | { | 687 | { |
646 | [IFLA_IPVLAN_MODE] = { .type = NLA_U16 }, | 688 | [IFLA_IPVLAN_MODE] = { .type = NLA_U16 }, |
689 | [IFLA_IPVLAN_FLAGS] = { .type = NLA_U16 }, | ||
647 | }; | 690 | }; |
648 | 691 | ||
649 | static struct rtnl_link_ops ipvlan_link_ops = { | 692 | static struct rtnl_link_ops ipvlan_link_ops = { |
diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h index b037e0ab1975..81f26473d728 100644 --- a/include/uapi/linux/if_link.h +++ b/include/uapi/linux/if_link.h | |||
@@ -465,6 +465,7 @@ enum macsec_validation_type { | |||
465 | enum { | 465 | enum { |
466 | IFLA_IPVLAN_UNSPEC, | 466 | IFLA_IPVLAN_UNSPEC, |
467 | IFLA_IPVLAN_MODE, | 467 | IFLA_IPVLAN_MODE, |
468 | IFLA_IPVLAN_FLAGS, | ||
468 | __IFLA_IPVLAN_MAX | 469 | __IFLA_IPVLAN_MAX |
469 | }; | 470 | }; |
470 | 471 | ||
@@ -477,6 +478,9 @@ enum ipvlan_mode { | |||
477 | IPVLAN_MODE_MAX | 478 | IPVLAN_MODE_MAX |
478 | }; | 479 | }; |
479 | 480 | ||
481 | #define IPVLAN_F_PRIVATE 0x01 | ||
482 | #define IPVLAN_F_VEPA 0x02 | ||
483 | |||
480 | /* VXLAN section */ | 484 | /* VXLAN section */ |
481 | enum { | 485 | enum { |
482 | IFLA_VXLAN_UNSPEC, | 486 | IFLA_VXLAN_UNSPEC, |