GRE (Generic Routing Encapsulation) is an industry standard for encapsulating data within an IP packet. Unlike IP protocol 7 (IPv4) GRE runs over IP protocol 47. It is often used to manipulate routing over non-broadcast networks or for sending multicast over IPSEC tunnels. This tech note was setup between a Juniper EX 4200 switch cluster and a Cisco 2621XM router. One of the issues with GRE traffic is its extra header which means payloads are reduced when you use it by an extra 4bytes (minimum).

So here is our basic topology. Remember we’re just using this to prove out the connectivity NOT to delve deeply into GRE itself or how we could use this to fix a ‘situation’. We’ll be bringing more of these technical guides as soon as we can write them using another 24 bit subnet From here we’ll have two loopback interfaces (one on each device) and we’ll setup the routing to divert traffic between each of these loopback interfaces across the tunnel.

.Screen shot 2011-05-28 at 22.19.00

First lets configure the EX switch ge-0/0/0 interface which is connected directly to the Cisco 2600. Notice the bit-wise mask at the end. Cisco’s recent NEXUS platform running the NX-OS also now uses the bitwise pattern for netmask...interesting ;-)

Screen shot 2011-05-28 at 22.31.29

Lets configure the loopback interface

Screen shot 2011-05-28 at 22.31.37

Right now we’ll configure the GRE interface itself. It doesn’t matter in the order of the next three configuration lines but you DO need them all ;-)

The source is the beginning of the tunnel from ‘this routers’ point of view’. As an analogy think of you in your car. You are driving toward a tunnel going under a river from Coolville to Duddberg. As far as you are concerned the start (source) the tunnel is in Coolville. When you return however the start of the tunnel is in Duddsberg. Same thing for traffic going into and out of your tunnel here.

Screen shot 2011-05-28 at 22.31.44

Now the destination. Remeber this is all relative and the other side will look the opposite.

Screen shot 2011-05-28 at 22.32.04

OK, now thats the tunnel built we need to ‘load it up’ with loely IPv4 traffic. So, just like a normal interface we’ll give it an IP address and a mask.

Screen shot 2011-05-28 at 22.42.19

Right JunOS side done now, lets nip over to the Cisco box and do the same.

Lets configure the Fast Ethernet 0/0 interface which is connected to the Juniper switch.

Screen shot 2011-05-28 at 22.47.14

Now we’ll configure the tunnel interface. For brevity I’ve taken a pumped all of the configuration in here but it follows EXACTLY the same sort of configuration as JunOS. Source IP of tunnel, desitination IP, IP address of the tunnel...done.

Screen shot 2011-05-28 at 23.03.44

Right so now thats up lets see if we can ping either side of the tunnel.

Cisco side first...

Screen shot 2011-05-28 at 22.38.30

Cool, now the Juniper side

Screen shot 2011-05-28 at 22.49.52

Awesome. Right but we’re pinging the sides of a point to point interface here which isn’t exactly right is it. So if we’re going to be ‘routing’ traffic through this tunnel and not just having a secondary route (whats the point in our topology anyway) we’ll need to give each side routes to one another. We’re going to route traffic for each sides Loopback interface through the tunnel.

Juniper side first

Screen shot 2011-05-28 at 22.53.06

...don’t forget the commit in JunOS. You know it never fails to impress me how Juniper got JunOS so right for administrators. If we screwed this up and the router happened to be 1000 miles away we’ve got options. Auto rollback is the best thing ever.

Now the Cisco side

Screen shot 2011-05-28 at 22.53.41

...if we screwed up IOS we’d be gone ;-) Of course we could always issue that great ‘reload in 10’ shortcut to save our ass.

Ok lets ping out over the tunnel interface.

Screen shot 2011-05-28 at 23.04.19

Now form Cisco side...just because we can

Screen shot 2011-05-28 at 23.05.23

What about some statistics to back that up man?! OK, here we go.

Right Juniper side first again. We got 6 in and out here...

Screen shot 2011-05-28 at 23.07.03

Cisco side...

Screen shot 2011-05-28 at 23.05.59

Job Done.

Thanks for Reading
View Comments
Hi all,

I know you're all desperate to find out how we configure Q-in-Q between IOS and JunOS and here we have it. You know, when we did this the effort required to get the Juniper EX part done was worrying. The Juniper documentation was pretty good and the Cisco Q-in-Q part is very well documented of course. This techguide will hopefully help some of you out there desperate to join these two great platforms as one.

First I guess we should provide a little background to Q-in-Q services. The idea is pretty simple, Q-in-Q is a process whereby a normal 802.1q frame is attached to another 802.1q header, hence the name. You will most likely use this is you have a requirement to say connect two layer 3 networks together which are separated by a layer 2 network. The layer 3 networks at each end may be in the same subnet and each of these geographically disparate networks can act as one.

Here is our challenge:


The laptop at the top of the diagram is connected to a Cisco 6509E and is in VLAN 186 with layer 3 network We have another laptop at the bottom of the diagram connected to a Juniper EX cluster again in VLAN 186 with network We need to get both of these laptops to operate within the same network despite being separated by a number of switches and hops. That is to say when I ping from one side to the other I want one hop to the destination.

Lets begin.

First we're hopefully all up to speed on VLANs and what they mean. If you need to read up on VLANs then take at look at our other techguides for a reminder. Lets create VLAN 186 on the first 6500 connected to the laptop and then place the port connected to the laptop into that vlan:

6500_FRONT(config#) vlan 186
6500_FRONT(config-vlan)# name X_SITE_INTERNET
6500_FRONT(config-vlan)# exit
6500_FRONT(config)# int g0/0
6500_FRONT(config-if)# switchport mode access
6500_FRONT(config-if)# switchport access vlan 186
6500_FRONT(config-if)# no shutdown
6500_FRONT(config-if)# end

So now lets take a look at the port connected between the FRONT and BACK 6500's. We need to configure this as an 802.1q port. Remember the Q-in-Q takes our 802.1q frames first.


So we take the VLAN 186 and only allow it on this port. Untagged traffic is also placed into VLAN 186 but this is necessary. We've forced the port to not use DTP (switchport nonegotiate) and we're manually configuring it as a trunk port. Forcing the port as a trunk is not required but is good practice.

Lets have a look at the 6500_BACK configuration for the port connected to the 6500_FRONT G4/11.


OK, looks like a lot of configuration here so lets go through the main lines. Now on a trunk port if you have a configuration for an access vlan (switchport access vlan) but configure 'switchport mode trunk' then the port os a trunk port and the acces vlan configuration is ignored. In our case we're configuring a dot1q tunnel port and therefore the access vlan IS IMPORTANT. So what are we saying here? Basically the 802.1q tagged traffic ingress into the port is left tagged (as if it were an access port with no tagging). The next line switchport mode dot1q-tunnel no performs the double tagging - we're going to be ramming tagged VLAN 186 traffic into VLAN 3043. The MTU is set to 9216 to accommodate for the double 802.1Q tag and should not be missed. 

We're disabling CDP so that we can tunnel CDP. What?! Well to help to explain this here is an example. When you have two directly connected cisco devices and CDP is running and enabled on these ports then you can 'see' the other device by issuing a 'show cdp neighbors'. This process is true also for Q-in-Q neighbors but we must turn off CDP between the two endpoints for the tunnel or else it would stomp all over the tunnel start points (in our example CDP would be tunnelled from 6500_FRONT but since the other startpoint is a Juniper device which doesn't undertsand CDP this step is unnecessary).

The l2ptotocol-tunnel allows us to send spanning-tree BPDU's down the Q-in-Q tunnel and CDP...we don't need them in our example but maybe you are creating a spanning-tree loop in your deployment so I think these lines are useful...just in case.

So now we are going to configure a normal run of the mill ordinary 802.1Q trunk link between the 6500_BACK and 3560 switches.

6500_BACK# configure terminal
6500_BACK(config)# interface g4/12
6500_BACK(config-if) switchport trunk encapsulation dot1q
6500_BACK(config-if) switchport mode trunk
6500_BACK(config-if) switchport trunk allowed vlan 1559,2127,3043,3738
6500_BACK(config-if) mtu 9216

So here we're just creating a normal trunk as we said. We're going to be trunking the Q-in-Q vlan 3043 we already created. Don't forget the jumbo frame MTU requirement. The other VLANs allowed on the trunk are for other things.

Right, at the other end of the link between the 6500 and 3560 we're going to again configure a normal bog standard trunk. 


On the 3560 there is one requirement to enable jumbo frames before this will work. In global configuration mode we issue:

3560(config)# system mtu jumbo

Then we need a reboot. Without this line the switch will not be able to support the minimum 1504 bytes required to transport the Q-in-Q frames. So when we're back we can move on - all should be fine so's just trunking.

Here is the configuration for the port connected to the Juniper EX stack.


So we're still trunking 3043...and some others but ignore those.

Now onto the Juniper EX stack dot1q-tunnel configuration.

First enable the protocol frame support.


Now lets create the VLAN - this took some time to get right int he Juniper documentation.


So we have created two vlans here. The first called X_SITE_INTERNET0 is carrying the Q-in-Q trunk traffic. Vlan XSITE_BACKBONE is carrying the untagged vlan 186 traffic.

Lets configure the port connected to the Cisco 3560. Again we need a dot1q trunk port and we'll restrict it to carrying only VLAN 3043.


So the last port configuration part if for the laptop port...


A quick 'show vlans XSITE_INTERNET_0 extensive'?


We see here that the 'Customer VLANs' are 186-186...or just 186 ;-) the ports ge-1/1/0.0 and ge-2/1/1.0 are the trunk ports connected to upstream Cisco switches (we've only looked at one of them...why do you think I had the STP stuff listed earlier ;-) ). The access ports are connected to host devices and are each in VLAN 186.

So there we go, IOS to JunOS using dot1q tunnelling. IT works, it's great tech, have fu.

View Comments
First you need to find an IPv6 broker. There are a few out there and we've chosen Hurricane Electric as our transit host of choice (they also offer a nifty certification at the end of a small test to make sure you are learning as you go).

So, go ahead and register for an account with your IPv6 broker of choice. They will probably offer you one /64 network which forms the 'link' between them and you and a /48 network which is for your LAN. Now in the IPv4 world we hate waste and normally you would subnet your point-to-point links with say a /30 subnet to give you a network, broadcast plus 2 host addresses. The IPv6 world is at this point not encouraging the use of /126 or /127 subnet masks for point-to-point links but instead is suggesting a /64. Of course this means that the point-to-point link now has 1.810 addresses available...ah no worries.

So you have your allocations so lets crack on configuring your router.

First things first you know that you are running IPv4 and your ISP probably doesn't support your desire to run IPv6 over their network. So we pick up that old Cisco trick of encapsulating the unsupported IPv6 traffic into IPv4 packets. A tunnel is perfect for this and luckily we can perform this 6-to-4 transformation using IPv6 inside both GRE or IP packets.

In the example below we have configured our tunnel interface and Tu0. We are setting the encapsulation type as IPv6IP (IPv6 inside an IP packet). Maybe (optional) we set a description on the interface. We set the local and remote IPv4 addresses for the tunnel. Now we enable IPv6 and then finally we give it the IPv6 address.

router> enable
router# configure terminal
router(config)# interface tunnel0
router(config)# ipv6 unicast-routing
router(config-if)# description My First IPv6 Tunnel
router(config-if)# tunnel source
router(config-if)# tunnel destination
router(config-if)# tunnel mode ipv6ip
router(config-if)# ipv6 enable
router(config-if)# ipv6 address

Here is a working example.


Thats it. So now lets have a look at the tunnel and make sure it's up and running.


Well that looks good but we still need to setup the routing table just like IPv4. We'll create a single static default route pointing all IPv6 traffic into the new tunnel interface. You could also use the IPv6 address of the broker side of the tunnel to save the recursion but the interface works fine.

router> enable
router# configure terminal
router(config)# ipv6 route ::0/0 tunnel0

Maybe we can do a ping to an ipv6 address to make sure all is well (please understand that our router has been configured to perform dns lookups against the google DNS servers using the 'ip domain-lookup' and 'ip name-server' commands in global configuration mode).


So that worked a treat and we're able to get out to the internet. There are two steps left. Firstly we need to enable your local LAN addressing now using the new /48 your broker allocated to you so lets do that now.

Now there is a question around what address do you use on the LAN from your /48 allocation. Well lets consider the IPv6 address for a moment. The first 64 bits are considered as the network. As an example our IPv6 /48 allocation looks like this:


The first 48 bits are 2001:0470:93FE and so we can subnet this into 65535 subnetworks working from 2001:470:93FE:1::/64 through to 2001:470:93FE:FFFF::/64. Do you see we are just changing the bits after the 93FE and the double colon ::? If you need to understand the IPv6 addressing then thats for another time, so for now lets move on. Choose a /64 network to work with...lets take 2001:470:93FE:1::/64.

router> enable
router# configure terminal
router(config)# interface G0/0
router(config-if)# description My Inside Interface
router(config-if)# ipv6 enable
router(config-if)# ipv6 address 2001:470:93FE:1::/64 eui-64

Whats the eui-64 all about? Well basically it creates a unique IPv6 address by taking the 48-bit MAC address of the interface, reversing the 7bit around, jamming another 16 bits of FFFE into the middle and putting the rest it to the end of your existing /64 address. Scared? Don't be, it's really nice. You can of course choose to fix your own IP address by doing this instead:

router(config-if)# ipv6 address 2001:470:93FE:1::1/64

We've chosen .1 as the router address and why not. So now thats done pick a host on behind this interface on your router, enable IPv6 on the stack and away you go. There are some other things in IPv6 like neighbor discovery (ICMPv6) which lists neighbor capability like DHCP servers and routing etc but thats for another time. This should be all you need to get routing IPv6.

So what about security? I'm guessing you're already using access lists on your router right? Maybe it's a standard or extended ACL, maybe it's reflexive or CBAC or even maybe ZBF? The point is that you have some sort of access control. IPv6 is no different so lets take a look at a quick and dirty access list for IPv6 using a reflexive ACL. We'll create two ACL's called TU0-INBOUND (Tunnel inbound) and TU0-OUTBOUND (tunnel Outbound). We'll basically just allow ping and then any outbound TCP and UDP traffic will be permitted and relexive. Anything inbound which was not initiated from inside the router OR a ping will be denied and logged.

ipv6 access-list TU0-INBOUND
permit icmp any any echo-request
permit icmp any any echo-reply
deny ipv6 any any log-input

ipv6 access-list TU0-OUTBOUND
permit icmp any any echo-reply
permit icmp any any echo-request
permit tcp any any reflect REFLECTOUT
permit udp any any reflect REFLECTOUT
deny ipv6 any any log-input

Then we should apply these to the tunnel0 interface.

router(config)# int tu0
router(config-if)# ipv6 traffic-filter TU0-INBOUND in
router(config-if)# ipv6 traffic-filter TU0-INBOUND out

So lets fire up a web browser and see if we can get to an IPv6 enabled website...this is


Now we'll escape back to priv exec mode and do a quick 'show access-lists' to see if we are matching rules.


Hey we have traffic matches.

Thats it. Enjoy

View Comments
© 2011

Cisco, IOS, CCNA, CCNP, CCIE are trademarks of Cisco Systems Inc.
JunOS, JNCIA, JNCIP, JNCIE are registered trademark of Juniper Networks Inc.